From 8cfa14e4111be28b93d8ecdc23ade741c10a3158 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Fri, 14 Jun 2019 09:09:37 -0300 Subject: [PATCH 001/207] Added Pycharm idea in gitignore --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 149f8680..e0353132 100644 --- a/.gitignore +++ b/.gitignore @@ -116,3 +116,6 @@ staticfiles/ # OS .DS_Store + +#Pycharm +.idea/ From 11ab934ede22fabd596d726fd1d0703612bf0e2a Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Mon, 17 Jun 2019 09:34:58 -0300 Subject: [PATCH 002/207] Added mixins update repository --- bothub/api/v1/views.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/bothub/api/v1/views.py b/bothub/api/v1/views.py index b9d3a903..ecacac6d 100644 --- a/bothub/api/v1/views.py +++ b/bothub/api/v1/views.py @@ -627,6 +627,7 @@ class NewRepositoryExampleViewSet( class RepositoryExampleViewSet( mixins.RetrieveModelMixin, mixins.DestroyModelMixin, + mixins.UpdateModelMixin, GenericViewSet): """ Manager repository example. @@ -636,6 +637,10 @@ class RepositoryExampleViewSet( delete: Delete repository example. + + update: + Update repository example. + """ queryset = RepositoryExample.objects serializer_class = RepositoryExampleSerializer @@ -643,6 +648,9 @@ class RepositoryExampleViewSet( RepositoryExamplePermission, ] + def perform_update(self, serializer): + serializer.save() + def perform_destroy(self, obj): if obj.deleted_in: raise APIException(_('Example already deleted')) From e8846728d5cecc24e823019d6e3548d40a27d70a Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Wed, 19 Jun 2019 11:03:56 -0300 Subject: [PATCH 003/207] Added test update repository --- bothub/api/v1/tests/test_example.py | 72 +++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/bothub/api/v1/tests/test_example.py b/bothub/api/v1/tests/test_example.py index ad26123e..97d06b62 100644 --- a/bothub/api/v1/tests/test_example.py +++ b/bothub/api/v1/tests/test_example.py @@ -499,6 +499,78 @@ def test_already_deleted(self): status.HTTP_500_INTERNAL_SERVER_ERROR) +class RepositoryExampleUpdateTestCase(TestCase): + def setUp(self): + self.factory = RequestFactory() + + self.owner, self.owner_token = create_user_and_token('owner') + self.user, self.user_token = create_user_and_token() + + self.repository = Repository.objects.create( + owner=self.owner, + name='Testing', + slug='test', + language=languages.LANGUAGE_EN) + self.example = RepositoryExample.objects.create( + repository_update=self.repository.current_update(), + text='hi') + + self.private_repository = Repository.objects.create( + owner=self.owner, + name='Testing Private', + slug='private', + language=languages.LANGUAGE_EN, + is_private=True) + self.private_example = RepositoryExample.objects.create( + repository_update=self.private_repository.current_update(), + text='hi') + + def request(self, example, token, data): + authorization_header = { + 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), + } + request = self.factory.patch( + '/api/example/{}/'.format(example.id), + json.dumps(data), + content_type='application/json', + **authorization_header) + response = RepositoryExampleViewSet.as_view( + {'patch': 'update'})(request, pk=example.id) + response.render() + content_data = json.loads(response.content) + return (response, content_data,) + + def test_okay(self): + text = 'teste' + intent = 'teste1234' + + response, content_data = self.request( + self.example, + self.owner_token, + {"text": text, "intent": intent} + ) + + self.assertEqual( + response.status_code, + status.HTTP_200_OK) + self.assertEqual( + content_data.get('text'), + text) + self.assertEqual( + content_data.get('intent'), + intent) + + def test_private_forbidden(self): + response, content_data = self.request( + self.private_example, + self.user_token, + {"text": 'teste', "intent": 'teste1234'}) + + self.assertEqual( + response.status_code, + status.HTTP_403_FORBIDDEN) + + class RepositoryEntitiesTestCase(TestCase): def setUp(self): self.factory = RequestFactory() From 5f19eaac06645ed6c474808c95345a475a4f7cc6 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Wed, 19 Jun 2019 12:07:45 -0300 Subject: [PATCH 004/207] [fix] Path src e-mail #253 --- bothub/authentication/models.py | 2 ++ .../templates/authentication/emails/welcome.html | 2 +- bothub/common/models.py | 4 ++++ bothub/common/templates/bothub/emails/base.html | 6 +++--- bothub/common/templates/common/emails/new_request.html | 2 +- bothub/common/templates/common/emails/request_approved.html | 2 +- bothub/settings.py | 1 + bothub/urls.py | 6 ++++++ docker-compose.yml | 1 + 9 files changed, 20 insertions(+), 6 deletions(-) diff --git a/bothub/authentication/models.py b/bothub/authentication/models.py index 922b3eea..dd288097 100644 --- a/bothub/authentication/models.py +++ b/bothub/authentication/models.py @@ -107,6 +107,7 @@ def send_welcome_email(self): return False context = { 'name': self.name, + 'base_url': settings.BASE_URL, } send_mail( _('Welcome to Bothub'), @@ -131,6 +132,7 @@ def send_reset_password_email(self): self.nickname, token) context = { + 'base_url': settings.BASE_URL, 'reset_url': reset_url, } send_mail( diff --git a/bothub/authentication/templates/authentication/emails/welcome.html b/bothub/authentication/templates/authentication/emails/welcome.html index ceebec55..d360b2ef 100644 --- a/bothub/authentication/templates/authentication/emails/welcome.html +++ b/bothub/authentication/templates/authentication/emails/welcome.html @@ -4,7 +4,7 @@ {% block before-content %}
- {% trans 'Welcome to Bothub' %} + {% trans 'Welcome to Bothub' %}

{% trans 'Welcome to Bothub' %}

{% endblock %} diff --git a/bothub/common/models.py b/bothub/common/models.py index 6eca13df..80f505f9 100644 --- a/bothub/common/models.py +++ b/bothub/common/models.py @@ -1109,6 +1109,7 @@ def send_new_role_email(self, responsible=None): responsible_name = responsible and responsible.name \ or self.repository.owner.name context = { + 'base_url': settings.BASE_URL, 'responsible_name': responsible_name, 'user_name': self.user.name, 'repository_name': self.repository.name, @@ -1187,6 +1188,7 @@ def send_new_request_email_to_admins(self): if not settings.SEND_EMAILS: return False context = { + 'base_url': settings.BASE_URL, 'user_name': self.user.name, 'repository_name': self.repository.name, 'text': self.text, @@ -1209,6 +1211,7 @@ def send_request_rejected_email(self): if not settings.SEND_EMAILS: return False context = { + 'base_url': settings.BASE_URL, 'repository_name': self.repository.name, } send_mail( @@ -1227,6 +1230,7 @@ def send_request_approved_email(self): if not settings.SEND_EMAILS: return False context = { + 'base_url': settings.BASE_URL, 'admin_name': self.approved_by.name, 'repository_name': self.repository.name, } diff --git a/bothub/common/templates/bothub/emails/base.html b/bothub/common/templates/bothub/emails/base.html index 85c2fa2b..03fc70fe 100644 --- a/bothub/common/templates/bothub/emails/base.html +++ b/bothub/common/templates/bothub/emails/base.html @@ -13,7 +13,7 @@
{% block content %} - Bothub + Bothub {% endblock %}
{% block before-content %}{% endblock %}
@@ -34,10 +34,10 @@ diff --git a/bothub/common/templates/common/emails/new_request.html b/bothub/common/templates/common/emails/new_request.html index 67bc9a77..3eb15ad6 100644 --- a/bothub/common/templates/common/emails/new_request.html +++ b/bothub/common/templates/common/emails/new_request.html @@ -4,7 +4,7 @@ {% block before-content %}
- {% trans 'New Authorization Request' %} + {% trans 'New Authorization Request' %}

{% trans 'New Authorization Request' %}

{% endblock %} diff --git a/bothub/common/templates/common/emails/request_approved.html b/bothub/common/templates/common/emails/request_approved.html index a5b76cf1..f0ec662e 100644 --- a/bothub/common/templates/common/emails/request_approved.html +++ b/bothub/common/templates/common/emails/request_approved.html @@ -4,7 +4,7 @@ {% block before-content %}
- {% trans 'Authorization Request Approved' %} + {% trans 'Authorization Request Approved' %}

{% trans 'Authorization Request Approved' %}

{% endblock %} diff --git a/bothub/settings.py b/bothub/settings.py index 303bd576..f2978642 100644 --- a/bothub/settings.py +++ b/bothub/settings.py @@ -23,6 +23,7 @@ default='*', cast=lambda v: [s.strip() for s in v.split(',')]) +BASE_URL = config('BASE_URL', default='') # Application definition diff --git a/bothub/urls.py b/bothub/urls.py index b3618f06..499c0e8c 100644 --- a/bothub/urls.py +++ b/bothub/urls.py @@ -29,6 +29,7 @@ def render_template(template_name, **kwargs): def wrapper(request): from django.shortcuts import render + print(request) return render(request, template_name, kwargs) return wrapper @@ -38,11 +39,13 @@ def wrapper(request): 'welcome/', render_template( 'authentication/emails/welcome.html', + base_url=settings.BASE_URL, name='Douglas')), path( 'new-role/', render_template( 'common/emails/new_role.html', + base_url=settings.BASE_URL, responsible_name='Douglas', user_name='Michael', repository_name='Repository 1', @@ -52,6 +55,7 @@ def wrapper(request): 'new-request/', render_template( 'common/emails/new_request.html', + base_url=settings.BASE_URL, user_name='Michael', repository_name='Repository 1', text='Lorem ipsum dolor sit amet, consectetur ' + @@ -64,11 +68,13 @@ def wrapper(request): 'request-rejected/', render_template( 'common/emails/request_rejected.html', + base_url=settings.BASE_URL, repository_name='Repository 1')), path( 'request-approved/', render_template( 'common/emails/request_approved.html', + base_url=settings.BASE_URL, admin_name='Douglas', repository_name='Repository 1', repository_url='http://localhost:8080/douglas/repo1/')), diff --git a/docker-compose.yml b/docker-compose.yml index 0729943a..d00c21b2 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -50,6 +50,7 @@ services: - CHECK_ACCESSIBLE_API_URL=${CHECK_ACCESSIBLE_API_URL} - SEND_EMAILS=${SEND_EMAILS:-true} - SUPPORTED_LANGUAGES=${SUPPORTED_LANGUAGES:-en|pt} + - BASE_URL=${BOTHUB_BACKEND_BASE_URL:-https://api.bothub.ti/} networks: From 9db320b838efdb99e7ec157e56dfa690a0cc17a4 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Wed, 19 Jun 2019 15:33:34 -0300 Subject: [PATCH 005/207] Remove print --- bothub/urls.py | 1 - 1 file changed, 1 deletion(-) diff --git a/bothub/urls.py b/bothub/urls.py index 499c0e8c..7f213eb1 100644 --- a/bothub/urls.py +++ b/bothub/urls.py @@ -29,7 +29,6 @@ def render_template(template_name, **kwargs): def wrapper(request): from django.shortcuts import render - print(request) return render(request, template_name, kwargs) return wrapper From d7f69f0b0493e1619c84b54fcdb92cb0d01098b6 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Wed, 19 Jun 2019 15:35:51 -0300 Subject: [PATCH 006/207] Remove perform update unnecessary --- bothub/api/v1/views.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/bothub/api/v1/views.py b/bothub/api/v1/views.py index ecacac6d..e83752fe 100644 --- a/bothub/api/v1/views.py +++ b/bothub/api/v1/views.py @@ -648,9 +648,6 @@ class RepositoryExampleViewSet( RepositoryExamplePermission, ] - def perform_update(self, serializer): - serializer.save() - def perform_destroy(self, obj): if obj.deleted_in: raise APIException(_('Example already deleted')) From be5fa8da4091898bc6aa3cde5daa825b6cc64b60 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Tue, 25 Jun 2019 10:43:57 -0300 Subject: [PATCH 007/207] Added test create evaluate --- bothub/api/v2/tests/test_evaluate.py | 100 +++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 bothub/api/v2/tests/test_evaluate.py diff --git a/bothub/api/v2/tests/test_evaluate.py b/bothub/api/v2/tests/test_evaluate.py new file mode 100644 index 00000000..b72449d8 --- /dev/null +++ b/bothub/api/v2/tests/test_evaluate.py @@ -0,0 +1,100 @@ +import json + +from django.test import RequestFactory +from django.test import TestCase +from rest_framework import status + +from bothub.api.v2.evaluate.views import EvaluateViewSet +from bothub.common.models import Repository +from bothub.common.models import RepositoryExample, RepositoryUpdate +from .utils import create_user_and_token + + +# TestCases + +class NewEvaluateTestCase(TestCase): + def setUp(self): + self.factory = RequestFactory() + + self.owner, self.owner_token = create_user_and_token('owner') + self.user, self.token = create_user_and_token() + self.authorization_header = { + 'HTTP_AUTHORIZATION': 'Token {}'.format(self.token.key), + } + + self.repository = Repository.objects.create( + owner=self.owner, + name='Testing', + slug='test', + language='en' + ) + + self.repository_update = RepositoryUpdate.objects.create( + repository=self.repository, + language='en', + algorithm='statistical_model', + ) + + self.example_1 = RepositoryExample.objects.create( + repository_update=self.repository_update, + text="teste", + intent="greet", + ) + + def request(self, data): + request = self.factory.post( + '/api/v2/evaluate/', + json.dumps(data), + content_type='application/json', + **self.authorization_header) + response = EvaluateViewSet.as_view({'post': 'create'})(request) + response.render() + content_data = json.loads(response.content) + return (response, content_data,) + + def test_okay(self): + response, content_data = self.request( + { + 'repository': str(self.repository.uuid), + 'text': 'haha', + 'language': 'en', + 'intent': 'greet', + 'entities': [] + } + ) + + self.assertEqual( + response.status_code, + status.HTTP_201_CREATED) + + def test_intent(self): + response, content_data = self.request( + { + 'repository': str(self.repository.uuid), + 'text': 'haha', + 'language': 'en', + 'intent': '', + 'entities': [] + } + ) + + self.assertEqual( + response.status_code, + status.HTTP_400_BAD_REQUEST) + self.assertIn('intent', content_data) + + def test_entities_not_exists(self): + response, content_data = self.request( + { + 'repository': str(self.repository.uuid), + 'text': 'haha', + 'language': 'en', + 'intent': 'greet', + 'entities': [{"entity": "hello", "start": 0, "end": 3}] + } + ) + self.assertEqual( + response.status_code, + status.HTTP_400_BAD_REQUEST) + + self.assertIn('entities', content_data) From 70f4950eab5effa9335527fedbaa6dc7040733bf Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Wed, 26 Jun 2019 08:44:33 -0300 Subject: [PATCH 008/207] Added test destroy evaluate --- bothub/api/v2/tests/test_evaluate.py | 85 +++++++++++++++++++++++++--- 1 file changed, 77 insertions(+), 8 deletions(-) diff --git a/bothub/api/v2/tests/test_evaluate.py b/bothub/api/v2/tests/test_evaluate.py index b72449d8..8fd7329e 100644 --- a/bothub/api/v2/tests/test_evaluate.py +++ b/bothub/api/v2/tests/test_evaluate.py @@ -5,8 +5,8 @@ from rest_framework import status from bothub.api.v2.evaluate.views import EvaluateViewSet -from bothub.common.models import Repository -from bothub.common.models import RepositoryExample, RepositoryUpdate +from bothub.common import languages +from bothub.common.models import RepositoryExample, RepositoryUpdate, Repository, RepositoryEvaluate from .utils import create_user_and_token @@ -26,18 +26,18 @@ def setUp(self): owner=self.owner, name='Testing', slug='test', - language='en' + language=languages.LANGUAGE_EN ) self.repository_update = RepositoryUpdate.objects.create( repository=self.repository, - language='en', + language=languages.LANGUAGE_EN, algorithm='statistical_model', ) self.example_1 = RepositoryExample.objects.create( repository_update=self.repository_update, - text="teste", + text="test", intent="greet", ) @@ -57,7 +57,7 @@ def test_okay(self): { 'repository': str(self.repository.uuid), 'text': 'haha', - 'language': 'en', + 'language': languages.LANGUAGE_EN, 'intent': 'greet', 'entities': [] } @@ -72,7 +72,7 @@ def test_intent(self): { 'repository': str(self.repository.uuid), 'text': 'haha', - 'language': 'en', + 'language': languages.LANGUAGE_EN, 'intent': '', 'entities': [] } @@ -88,7 +88,7 @@ def test_entities_not_exists(self): { 'repository': str(self.repository.uuid), 'text': 'haha', - 'language': 'en', + 'language': languages.LANGUAGE_EN, 'intent': 'greet', 'entities': [{"entity": "hello", "start": 0, "end": 3}] } @@ -98,3 +98,72 @@ def test_entities_not_exists(self): status.HTTP_400_BAD_REQUEST) self.assertIn('entities', content_data) + + +class EvaluateDestroyTestCase(TestCase): + def setUp(self): + self.factory = RequestFactory() + + self.owner, self.owner_token = create_user_and_token('owner') + self.user, self.token = create_user_and_token() + + self.repository = Repository.objects.create( + owner=self.owner, + name='Testing', + slug='test', + language=languages.LANGUAGE_EN + ) + + self.repository_update = RepositoryUpdate.objects.create( + repository=self.repository, + language='en', + algorithm='statistical_model', + ) + + self.example_1 = RepositoryExample.objects.create( + repository_update=self.repository_update, + text="test", + intent="greet", + ) + + self.repository_evaluate = RepositoryEvaluate.objects.create( + repository_update=self.repository_update, + text="test", + intent="greet" + ) + + def request(self, token): + authorization_header = { + 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), + } + + request = self.factory.delete( + '/api/v2/evaluate/{}/'.format(self.repository_evaluate.id), + **authorization_header) + response = EvaluateViewSet.as_view( + {'delete': 'destroy'})(request, pk=self.repository_evaluate.id) + return response + + def test_okay(self): + response = self.request(self.owner_token) + + self.assertEqual( + response.status_code, + status.HTTP_204_NO_CONTENT) + + def test_private_okay(self): + response = self.request(self.token) + self.assertEqual( + response.status_code, + status.HTTP_403_FORBIDDEN) + + def test_already_deleted(self): + self.repository_evaluate.delete() + response = self.request(self.owner_token) + + self.assertEqual( + response.status_code, + status.HTTP_204_NO_CONTENT) + self.assertIsNotNone( + self.repository_evaluate.deleted_in + ) From a2aaa03f98cabb2ca8f995d8a56aa7249a5f4f49 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Thu, 27 Jun 2019 11:17:44 -0300 Subject: [PATCH 009/207] [fix] Permissions repository --- bothub/api/v2/repository/permissions.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/bothub/api/v2/repository/permissions.py b/bothub/api/v2/repository/permissions.py index 411247fd..0f1d5d8b 100644 --- a/bothub/api/v2/repository/permissions.py +++ b/bothub/api/v2/repository/permissions.py @@ -7,9 +7,12 @@ class RepositoryPermission(permissions.BasePermission): def has_object_permission(self, request, view, obj): authorization = obj.get_user_authorization(request.user) - if request.method in READ_METHODS: + if request.method in READ_METHODS and not request.user.is_authenticated: return authorization.can_read + if request.user.is_authenticated: + if request.method in READ_METHODS: + return authorization.can_read if request.method in WRITE_METHODS: return authorization.can_write return authorization.is_admin From 26c6faea8efa7600921894e594687002de575af2 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Thu, 27 Jun 2019 11:19:39 -0300 Subject: [PATCH 010/207] [fix] Permissions Evaluate --- bothub/api/v2/evaluate/permissions.py | 43 +++++++++++++++++---------- bothub/api/v2/evaluate/views.py | 1 + 2 files changed, 28 insertions(+), 16 deletions(-) diff --git a/bothub/api/v2/evaluate/permissions.py b/bothub/api/v2/evaluate/permissions.py index 79fbb631..9a79901e 100644 --- a/bothub/api/v2/evaluate/permissions.py +++ b/bothub/api/v2/evaluate/permissions.py @@ -1,29 +1,40 @@ from rest_framework import permissions +from bothub.common.models import Repository from .. import READ_METHODS from .. import WRITE_METHODS class RepositoryEvaluatePermission(permissions.BasePermission): - def has_object_permission(self, request, view, obj): - authorization = obj.repository_update. \ - repository.get_user_authorization(request.user) - if request.method in READ_METHODS: - return authorization.can_read - if request.user.is_authenticated: - if request.method in WRITE_METHODS: - return authorization.can_write - return authorization.is_admin - return False + def has_permission(self, request, view): + try: + repository = Repository.objects.get(uuid=request.GET.get('repository_uuid')) + authorization = repository.get_user_authorization(request.user) + + if request.method in READ_METHODS and not request.user.is_authenticated: + return authorization.can_read + + if request.user.is_authenticated: + if request.method in READ_METHODS: + return authorization.can_read + if request.method in WRITE_METHODS: + return authorization.can_write + return authorization.is_admin + return False + except Repository.DoesNotExist: + return False class RepositoryEvaluateResultPermission(permissions.BasePermission): - def has_object_permission(self, request, view, obj): - authorization = obj.repository_update. \ - repository.get_user_authorization(request.user) + def has_permission(self, request, view): + try: + repository = Repository.objects.get(uuid=request.GET.get('repository_uuid')) + authorization = repository.get_user_authorization(request.user) - if request.method in READ_METHODS: - return authorization.can_read - return authorization.can_contribute + if request.method in READ_METHODS: + return authorization.can_read + return authorization.can_contribute + except Repository.DoesNotExist: + return False diff --git a/bothub/api/v2/evaluate/views.py b/bothub/api/v2/evaluate/views.py index 1987872c..5bb24b07 100644 --- a/bothub/api/v2/evaluate/views.py +++ b/bothub/api/v2/evaluate/views.py @@ -32,6 +32,7 @@ class EvaluateViewSet( """ Manager evaluate (tests). """ + lookup_fields = ('pk', 'repository_uuid') queryset = RepositoryEvaluate.objects serializer_class = RepositoryEvaluateSerializer permission_classes = [ From 0c940c6bea31d9a38204c5fde635e988ff560d98 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Thu, 27 Jun 2019 11:21:00 -0300 Subject: [PATCH 011/207] [fix] test evaluate --- bothub/api/v2/tests/test_evaluate.py | 37 +++++++++++++++++++--------- 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/bothub/api/v2/tests/test_evaluate.py b/bothub/api/v2/tests/test_evaluate.py index 8fd7329e..b5b6db4a 100644 --- a/bothub/api/v2/tests/test_evaluate.py +++ b/bothub/api/v2/tests/test_evaluate.py @@ -18,9 +18,6 @@ def setUp(self): self.owner, self.owner_token = create_user_and_token('owner') self.user, self.token = create_user_and_token() - self.authorization_header = { - 'HTTP_AUTHORIZATION': 'Token {}'.format(self.token.key), - } self.repository = Repository.objects.create( owner=self.owner, @@ -41,12 +38,15 @@ def setUp(self): intent="greet", ) - def request(self, data): + def request(self, data, token): + authorization_header = { + 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), + } request = self.factory.post( - '/api/v2/evaluate/', + '/api/v2/evaluate/?repository_uuid={}'.format(self.repository.uuid), json.dumps(data), content_type='application/json', - **self.authorization_header) + **authorization_header) response = EvaluateViewSet.as_view({'post': 'create'})(request) response.render() content_data = json.loads(response.content) @@ -60,7 +60,7 @@ def test_okay(self): 'language': languages.LANGUAGE_EN, 'intent': 'greet', 'entities': [] - } + }, self.owner_token ) self.assertEqual( @@ -75,7 +75,7 @@ def test_intent(self): 'language': languages.LANGUAGE_EN, 'intent': '', 'entities': [] - } + }, self.owner_token ) self.assertEqual( @@ -91,7 +91,7 @@ def test_entities_not_exists(self): 'language': languages.LANGUAGE_EN, 'intent': 'greet', 'entities': [{"entity": "hello", "start": 0, "end": 3}] - } + }, self.owner_token ) self.assertEqual( response.status_code, @@ -99,6 +99,20 @@ def test_entities_not_exists(self): self.assertIn('entities', content_data) + def test_private_okay(self): + response, content_data = self.request( + { + 'repository': str(self.repository.uuid), + 'text': 'haha', + 'language': languages.LANGUAGE_EN, + 'intent': 'greet', + 'entities': [] + }, self.token + ) + self.assertEqual( + response.status_code, + status.HTTP_403_FORBIDDEN) + class EvaluateDestroyTestCase(TestCase): def setUp(self): @@ -136,12 +150,11 @@ def request(self, token): authorization_header = { 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), } - request = self.factory.delete( - '/api/v2/evaluate/{}/'.format(self.repository_evaluate.id), + '/api/v2/evaluate/{}/?repository_uuid={}'.format(self.repository_evaluate.id, self.repository.uuid), **authorization_header) response = EvaluateViewSet.as_view( - {'delete': 'destroy'})(request, pk=self.repository_evaluate.id) + {'delete': 'destroy'})(request, pk=self.repository_evaluate.id, repository_uuid=self.repository.uuid) return response def test_okay(self): From 52aad6357edb5aad291326165f44a30fc59367bf Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Thu, 27 Jun 2019 11:37:59 -0300 Subject: [PATCH 012/207] Added test update evaluate --- bothub/api/v2/tests/test_evaluate.py | 79 ++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/bothub/api/v2/tests/test_evaluate.py b/bothub/api/v2/tests/test_evaluate.py index b5b6db4a..b80661ec 100644 --- a/bothub/api/v2/tests/test_evaluate.py +++ b/bothub/api/v2/tests/test_evaluate.py @@ -180,3 +180,82 @@ def test_already_deleted(self): self.assertIsNotNone( self.repository_evaluate.deleted_in ) + + +class EvaluateUpdateTestCase(TestCase): + def setUp(self): + self.factory = RequestFactory() + + self.owner, self.owner_token = create_user_and_token('owner') + self.user, self.token = create_user_and_token() + + self.repository = Repository.objects.create( + owner=self.owner, + name='Testing', + slug='test', + language=languages.LANGUAGE_EN + ) + + self.repository_update = RepositoryUpdate.objects.create( + repository=self.repository, + language='en', + algorithm='statistical_model', + ) + + self.example_1 = RepositoryExample.objects.create( + repository_update=self.repository_update, + text="test", + intent="greet", + ) + + self.repository_evaluate = RepositoryEvaluate.objects.create( + repository_update=self.repository_update, + text="test", + intent="greet" + ) + + def request(self, data, token): + authorization_header = { + 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), + } + request = self.factory.patch( + '/api/v2/evaluate/{}/?repository_uuid={}'.format(self.repository_evaluate.id, self.repository.uuid), + json.dumps(data), + content_type='application/json', + **authorization_header) + response = EvaluateViewSet.as_view( + {'patch': 'update'})(request, pk=self.repository_evaluate.id, repository_uuid=self.repository.uuid) + response.render() + content_data = json.loads(response.content) + + return (response, content_data,) + + def test_okay(self): + text = 'testing' + response, content_data = self.request( + { + 'repository': str(self.repository.uuid), + 'text': text, + 'language': languages.LANGUAGE_EN, + 'intent': 'greet', + 'entities': [] + }, self.owner_token + ) + self.assertEqual(content_data['text'], text) + self.assertEqual( + response.status_code, + status.HTTP_200_OK) + + def test_private_okay(self): + response, content_data = self.request( + { + 'repository': str(self.repository.uuid), + 'text': 'testing', + 'language': languages.LANGUAGE_EN, + 'intent': 'greet', + 'entities': [] + }, self.token) + self.assertEqual( + response.status_code, + status.HTTP_403_FORBIDDEN) + From 849bd0a8e3a8a4d3e6c2709a1aed1c65c620b0da Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Thu, 27 Jun 2019 12:01:07 -0300 Subject: [PATCH 013/207] Update permission evaluate results --- bothub/api/v2/evaluate/views.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bothub/api/v2/evaluate/views.py b/bothub/api/v2/evaluate/views.py index 5bb24b07..d162df25 100644 --- a/bothub/api/v2/evaluate/views.py +++ b/bothub/api/v2/evaluate/views.py @@ -1,6 +1,6 @@ from rest_framework.viewsets import GenericViewSet from rest_framework import mixins -from rest_framework.permissions import IsAuthenticatedOrReadOnly +from rest_framework.permissions import IsAuthenticatedOrReadOnly, IsAuthenticated from rest_framework.filters import SearchFilter from rest_framework.filters import OrderingFilter @@ -68,7 +68,7 @@ class ResultsListViewSet( queryset = RepositoryEvaluateResult.objects serializer_class = RepositoryEvaluateResultVersionsSerializer permission_classes = [ - IsAuthenticatedOrReadOnly, + IsAuthenticated, RepositoryEvaluateResultPermission, ] filter_class = EvaluateResultsFilter From 0dd590d55cc680af05f8e22371ac923223b0eaae Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Fri, 28 Jun 2019 08:56:20 -0300 Subject: [PATCH 014/207] Added test list evaluate results --- bothub/api/v2/evaluate/views.py | 1 + bothub/api/v2/tests/test_evaluate.py | 182 ++++++++++++++++++++++++++- 2 files changed, 181 insertions(+), 2 deletions(-) diff --git a/bothub/api/v2/evaluate/views.py b/bothub/api/v2/evaluate/views.py index d162df25..4d56fa50 100644 --- a/bothub/api/v2/evaluate/views.py +++ b/bothub/api/v2/evaluate/views.py @@ -66,6 +66,7 @@ class ResultsListViewSet( GenericViewSet): queryset = RepositoryEvaluateResult.objects + lookup_fields = ('repository_uuid',) serializer_class = RepositoryEvaluateResultVersionsSerializer permission_classes = [ IsAuthenticated, diff --git a/bothub/api/v2/tests/test_evaluate.py b/bothub/api/v2/tests/test_evaluate.py index b80661ec..e7ea4c81 100644 --- a/bothub/api/v2/tests/test_evaluate.py +++ b/bothub/api/v2/tests/test_evaluate.py @@ -4,9 +4,11 @@ from django.test import TestCase from rest_framework import status -from bothub.api.v2.evaluate.views import EvaluateViewSet +from bothub.api.v2.evaluate.views import EvaluateViewSet, ResultsListViewSet from bothub.common import languages -from bothub.common.models import RepositoryExample, RepositoryUpdate, Repository, RepositoryEvaluate +from bothub.common.models import RepositoryExample, RepositoryUpdate, Repository, RepositoryEvaluate, \ + RepositoryEvaluateResultScore, RepositoryEvaluateResult, RepositoryEvaluateResultIntent, \ + RepositoryEvaluateResultEntity from .utils import create_user_and_token @@ -259,3 +261,179 @@ def test_private_okay(self): response.status_code, status.HTTP_403_FORBIDDEN) + +class GetEvaluateResultTestCase(TestCase): + def setUp(self): + self.factory = RequestFactory() + + self.owner, self.owner_token = create_user_and_token('owner') + self.user, self.token = create_user_and_token() + + self.repository = Repository.objects.create( + owner=self.owner, + name='Testing', + slug='test', + language=languages.LANGUAGE_EN + ) + + for x in range(0, 2): + intent_results = RepositoryEvaluateResultScore.objects.create( + f1_score=0.976, + precision=0.978, + accuracy=0.976, + ) + + entity_results = RepositoryEvaluateResultScore.objects.create( + f1_score=0.977, + precision=0.978, + accuracy=0.978, + ) + + evaluate_log = [ + { + "text": "hey", + "intent": "greet", + "intent_prediction": { + "name": "greet", + "confidence": 0.9263743763408538 + }, + "status": "success" + }, + { + "text": "howdy", + "intent": "greet", + "intent_prediction": { + "name": "greet", + "confidence": 0.8099720606047796 + }, + "status": "success" + }, + { + "text": "hey there", + "intent": "greet", + "intent_prediction": { + "name": "greet", + "confidence": 0.8227075176309955 + }, + "status": "success" + }, + { + "text": "test with nlu", + "intent": "restaurant_search", + "intent_prediction": { + "name": "goodbye", + "confidence": 0.3875259420712092 + }, + "status": "error" + } + ] + + sample_url = 'https://s3.amazonaws.com/bothub-sample' + evaluate_result = RepositoryEvaluateResult.objects.create( + repository_update=self.repository.current_update(), + intent_results=intent_results, + entity_results=entity_results, + matrix_chart='{}/confmat.png'.format(sample_url), + confidence_chart='{}/hist.png'.format(sample_url), + log=json.dumps(evaluate_log), + ) + + intent_score_1 = RepositoryEvaluateResultScore.objects.create( + precision=1.0, + recall=1.0, + f1_score=1.0, + support=11, + ) + + intent_score_2 = RepositoryEvaluateResultScore.objects.create( + precision=0.89, + recall=1.0, + f1_score=0.94, + support=8, + ) + + intent_score_3 = RepositoryEvaluateResultScore.objects.create( + precision=1.0, + recall=1.0, + f1_score=1.0, + support=8, + ) + + intent_score_4 = RepositoryEvaluateResultScore.objects.create( + precision=1.0, + recall=0.93, + f1_score=0.97, + support=15, + ) + + RepositoryEvaluateResultIntent.objects.create( + evaluate_result=evaluate_result, + intent='affirm', + score=intent_score_1, + ) + + RepositoryEvaluateResultIntent.objects.create( + evaluate_result=evaluate_result, + intent='goodbye', + score=intent_score_2, + ) + + RepositoryEvaluateResultIntent.objects.create( + evaluate_result=evaluate_result, + intent='greet', + score=intent_score_3, + ) + + RepositoryEvaluateResultIntent.objects.create( + evaluate_result=evaluate_result, + intent='restaurant_search', + score=intent_score_4, + ) + + entity_score_1 = RepositoryEvaluateResultScore.objects.create( + precision=1.0, + recall=0.90, + f1_score=0.95, + support=10, + ) + + entity_score_2 = RepositoryEvaluateResultScore.objects.create( + precision=1.0, + recall=0.75, + f1_score=0.86, + support=8, + ) + + RepositoryEvaluateResultEntity.objects.create( + evaluate_result=evaluate_result, + entity='cuisine', + score=entity_score_1, + ) + + RepositoryEvaluateResultEntity.objects.create( + evaluate_result=evaluate_result, + entity='greet', + score=entity_score_2, + ) + + + def request(self, token): + authorization_header = { + 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), + } + request = self.factory.get( + '/api/v2/evaluate/results/?repository_uuid={}'.format(self.repository.uuid), + **authorization_header) + response = ResultsListViewSet.as_view({'get': 'list'})(request, repository_uuid=self.repository.uuid) + response.render() + content_data = json.loads(response.content) + return (response, content_data,) + + def test_okay(self): + response, content_data = self.request(self.owner_token) + self.assertEqual(content_data['count'], 2) + self.assertEqual(len(content_data['results']), 2) + self.assertEqual( + response.status_code, + status.HTTP_200_OK) + From b504ed3883a3b7ed1e2453fb036ef2610567ad65 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Fri, 28 Jun 2019 08:57:00 -0300 Subject: [PATCH 015/207] Added test list evaluate results --- bothub/api/v2/tests/test_evaluate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bothub/api/v2/tests/test_evaluate.py b/bothub/api/v2/tests/test_evaluate.py index e7ea4c81..e01139fe 100644 --- a/bothub/api/v2/tests/test_evaluate.py +++ b/bothub/api/v2/tests/test_evaluate.py @@ -262,7 +262,7 @@ def test_private_okay(self): status.HTTP_403_FORBIDDEN) -class GetEvaluateResultTestCase(TestCase): +class ListEvaluateResultTestCase(TestCase): def setUp(self): self.factory = RequestFactory() From 77ee3f690bc2146ef8a2b8d0383cff09f00969fc Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Fri, 28 Jun 2019 09:57:01 -0300 Subject: [PATCH 016/207] Added test list evaluate --- bothub/api/v2/tests/test_evaluate.py | 54 ++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/bothub/api/v2/tests/test_evaluate.py b/bothub/api/v2/tests/test_evaluate.py index e01139fe..70940f99 100644 --- a/bothub/api/v2/tests/test_evaluate.py +++ b/bothub/api/v2/tests/test_evaluate.py @@ -14,6 +14,60 @@ # TestCases +class ListEvaluateTestCase(TestCase): + def setUp(self): + self.factory = RequestFactory() + + self.owner, self.owner_token = create_user_and_token('owner') + self.user, self.token = create_user_and_token() + + self.repository = Repository.objects.create( + owner=self.owner, + name='Testing', + slug='test', + language=languages.LANGUAGE_EN + ) + + self.repository_update = RepositoryUpdate.objects.create( + repository=self.repository, + language=languages.LANGUAGE_EN, + algorithm='statistical_model', + ) + + self.example_1 = RepositoryExample.objects.create( + repository_update=self.repository_update, + text="test", + intent="greet", + ) + + self.repository_evaluate = RepositoryEvaluate.objects.create( + repository_update=self.repository_update, + text="test", + intent="greet" + ) + + def request(self, token): + authorization_header = { + 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), + } + request = self.factory.get( + '/api/v2/evaluate/?repository_uuid={}'.format(self.repository.uuid), + **authorization_header) + response = EvaluateViewSet.as_view({'get': 'list'})(request, repository_uuid=self.repository.uuid) + response.render() + content_data = json.loads(response.content) + return (response, content_data,) + + def test_okay(self): + response, content_data = self.request(self.owner_token) + + self.assertEqual(content_data['count'], 1) + self.assertEqual(len(content_data['results']), 1) + self.assertEqual( + response.status_code, + status.HTTP_200_OK) + + class NewEvaluateTestCase(TestCase): def setUp(self): self.factory = RequestFactory() From 5ed605f7b220ab3f1a771fff2a8fa6e8541f1725 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Fri, 28 Jun 2019 09:58:57 -0300 Subject: [PATCH 017/207] Update test evaluate PEP8 --- bothub/api/v2/tests/test_evaluate.py | 1 - 1 file changed, 1 deletion(-) diff --git a/bothub/api/v2/tests/test_evaluate.py b/bothub/api/v2/tests/test_evaluate.py index 70940f99..e69ed9a5 100644 --- a/bothub/api/v2/tests/test_evaluate.py +++ b/bothub/api/v2/tests/test_evaluate.py @@ -470,7 +470,6 @@ def setUp(self): score=entity_score_2, ) - def request(self, token): authorization_header = { 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), From 88ba1b87d178708141d774648bd8f74b076f04b9 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Fri, 28 Jun 2019 10:25:29 -0300 Subject: [PATCH 018/207] [fix] PEP8 --- bothub/api/v2/evaluate/permissions.py | 11 +++-- bothub/api/v2/evaluate/views.py | 3 +- bothub/api/v2/repository/permissions.py | 3 +- bothub/api/v2/tests/test_evaluate.py | 61 ++++++++++++++++++------- 4 files changed, 57 insertions(+), 21 deletions(-) diff --git a/bothub/api/v2/evaluate/permissions.py b/bothub/api/v2/evaluate/permissions.py index 9a79901e..a2d720a5 100644 --- a/bothub/api/v2/evaluate/permissions.py +++ b/bothub/api/v2/evaluate/permissions.py @@ -9,10 +9,13 @@ class RepositoryEvaluatePermission(permissions.BasePermission): def has_permission(self, request, view): try: - repository = Repository.objects.get(uuid=request.GET.get('repository_uuid')) + repository = Repository.objects.get( + uuid=request.GET.get('repository_uuid') + ) authorization = repository.get_user_authorization(request.user) - if request.method in READ_METHODS and not request.user.is_authenticated: + if request.method in READ_METHODS and \ + not request.user.is_authenticated: return authorization.can_read if request.user.is_authenticated: @@ -30,7 +33,9 @@ class RepositoryEvaluateResultPermission(permissions.BasePermission): def has_permission(self, request, view): try: - repository = Repository.objects.get(uuid=request.GET.get('repository_uuid')) + repository = Repository.objects.get( + uuid=request.GET.get('repository_uuid') + ) authorization = repository.get_user_authorization(request.user) if request.method in READ_METHODS: diff --git a/bothub/api/v2/evaluate/views.py b/bothub/api/v2/evaluate/views.py index 4d56fa50..c36cf1c6 100644 --- a/bothub/api/v2/evaluate/views.py +++ b/bothub/api/v2/evaluate/views.py @@ -1,6 +1,7 @@ from rest_framework.viewsets import GenericViewSet from rest_framework import mixins -from rest_framework.permissions import IsAuthenticatedOrReadOnly, IsAuthenticated +from rest_framework.permissions import \ + IsAuthenticatedOrReadOnly, IsAuthenticated from rest_framework.filters import SearchFilter from rest_framework.filters import OrderingFilter diff --git a/bothub/api/v2/repository/permissions.py b/bothub/api/v2/repository/permissions.py index 0f1d5d8b..9b3b006f 100644 --- a/bothub/api/v2/repository/permissions.py +++ b/bothub/api/v2/repository/permissions.py @@ -7,7 +7,8 @@ class RepositoryPermission(permissions.BasePermission): def has_object_permission(self, request, view, obj): authorization = obj.get_user_authorization(request.user) - if request.method in READ_METHODS and not request.user.is_authenticated: + if request.method in READ_METHODS and \ + not request.user.is_authenticated: return authorization.can_read if request.user.is_authenticated: diff --git a/bothub/api/v2/tests/test_evaluate.py b/bothub/api/v2/tests/test_evaluate.py index e69ed9a5..6a411adb 100644 --- a/bothub/api/v2/tests/test_evaluate.py +++ b/bothub/api/v2/tests/test_evaluate.py @@ -6,8 +6,9 @@ from bothub.api.v2.evaluate.views import EvaluateViewSet, ResultsListViewSet from bothub.common import languages -from bothub.common.models import RepositoryExample, RepositoryUpdate, Repository, RepositoryEvaluate, \ - RepositoryEvaluateResultScore, RepositoryEvaluateResult, RepositoryEvaluateResultIntent, \ +from bothub.common.models import RepositoryExample, RepositoryUpdate, \ + Repository, RepositoryEvaluate, RepositoryEvaluateResultScore, \ + RepositoryEvaluateResult, RepositoryEvaluateResultIntent, \ RepositoryEvaluateResultEntity from .utils import create_user_and_token @@ -51,9 +52,14 @@ def request(self, token): 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), } request = self.factory.get( - '/api/v2/evaluate/?repository_uuid={}'.format(self.repository.uuid), - **authorization_header) - response = EvaluateViewSet.as_view({'get': 'list'})(request, repository_uuid=self.repository.uuid) + '/api/v2/evaluate/?repository_uuid={}'.format( + self.repository.uuid + ), **authorization_header + ) + response = EvaluateViewSet.as_view({'get': 'list'})( + request, + repository_uuid=self.repository.uuid + ) response.render() content_data = json.loads(response.content) return (response, content_data,) @@ -99,10 +105,13 @@ def request(self, data, token): 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), } request = self.factory.post( - '/api/v2/evaluate/?repository_uuid={}'.format(self.repository.uuid), + '/api/v2/evaluate/?repository_uuid={}'.format( + self.repository.uuid + ), json.dumps(data), content_type='application/json', - **authorization_header) + **authorization_header + ) response = EvaluateViewSet.as_view({'post': 'create'})(request) response.render() content_data = json.loads(response.content) @@ -207,10 +216,17 @@ def request(self, token): 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), } request = self.factory.delete( - '/api/v2/evaluate/{}/?repository_uuid={}'.format(self.repository_evaluate.id, self.repository.uuid), - **authorization_header) + '/api/v2/evaluate/{}/?repository_uuid={}'.format( + self.repository_evaluate.id, + self.repository.uuid + ), **authorization_header + ) response = EvaluateViewSet.as_view( - {'delete': 'destroy'})(request, pk=self.repository_evaluate.id, repository_uuid=self.repository.uuid) + {'delete': 'destroy'})( + request, + pk=self.repository_evaluate.id, + repository_uuid=self.repository.uuid + ) return response def test_okay(self): @@ -275,12 +291,20 @@ def request(self, data, token): 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), } request = self.factory.patch( - '/api/v2/evaluate/{}/?repository_uuid={}'.format(self.repository_evaluate.id, self.repository.uuid), + '/api/v2/evaluate/{}/?repository_uuid={}'.format( + self.repository_evaluate.id, + self.repository.uuid + ), json.dumps(data), content_type='application/json', - **authorization_header) + **authorization_header + ) response = EvaluateViewSet.as_view( - {'patch': 'update'})(request, pk=self.repository_evaluate.id, repository_uuid=self.repository.uuid) + {'patch': 'update'})( + request, + pk=self.repository_evaluate.id, + repository_uuid=self.repository.uuid + ) response.render() content_data = json.loads(response.content) @@ -475,9 +499,14 @@ def request(self, token): 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), } request = self.factory.get( - '/api/v2/evaluate/results/?repository_uuid={}'.format(self.repository.uuid), - **authorization_header) - response = ResultsListViewSet.as_view({'get': 'list'})(request, repository_uuid=self.repository.uuid) + '/api/v2/evaluate/results/?repository_uuid={}'.format( + self.repository.uuid + ), **authorization_header + ) + response = ResultsListViewSet.as_view({'get': 'list'})( + request, + repository_uuid=self.repository.uuid + ) response.render() content_data = json.loads(response.content) return (response, content_data,) From f678bb2f41682a9089b4972b7361aff463fbdf32 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Fri, 28 Jun 2019 10:27:52 -0300 Subject: [PATCH 019/207] [fix] PEP8 --- bothub/api/v2/tests/test_evaluate.py | 1 - 1 file changed, 1 deletion(-) diff --git a/bothub/api/v2/tests/test_evaluate.py b/bothub/api/v2/tests/test_evaluate.py index 6a411adb..470b9d27 100644 --- a/bothub/api/v2/tests/test_evaluate.py +++ b/bothub/api/v2/tests/test_evaluate.py @@ -518,4 +518,3 @@ def test_okay(self): self.assertEqual( response.status_code, status.HTTP_200_OK) - From c7364047813ec37720494775bc20274c59b71fbc Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Mon, 1 Jul 2019 09:15:31 -0300 Subject: [PATCH 020/207] Update class MyRepositories to SearchRepositories --- bothub/api/v1/routers.py | 4 ++-- bothub/api/v1/views.py | 12 ++++++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/bothub/api/v1/routers.py b/bothub/api/v1/routers.py index d3934cf4..ec708a61 100644 --- a/bothub/api/v1/routers.py +++ b/bothub/api/v1/routers.py @@ -1,7 +1,7 @@ from rest_framework import routers from .views import NewRepositoryViewSet -from .views import MyRepositoriesViewSet +from .views import SearchRepositoriesViewSet from .views import RepositoryViewSet from .views import NewRepositoryExampleViewSet from .views import RepositoryExampleViewSet @@ -99,7 +99,7 @@ def get_lookup_regex(self, viewset, lookup_prefix=''): router = Router() router.register('repository/new', NewRepositoryViewSet) -router.register('my-repositories', MyRepositoriesViewSet) +router.register('search-repositories', SearchRepositoriesViewSet) router.register('repository', RepositoryViewSet) router.register('example/new', NewRepositoryExampleViewSet) router.register('example', RepositoryExampleViewSet) diff --git a/bothub/api/v1/views.py b/bothub/api/v1/views.py index b9d3a903..0506813a 100644 --- a/bothub/api/v1/views.py +++ b/bothub/api/v1/views.py @@ -404,7 +404,7 @@ def create(self, request, *args, **kwargs): headers=headers) -class MyRepositoriesViewSet( +class SearchRepositoriesViewSet( mixins.ListModelMixin, GenericViewSet): """ @@ -415,7 +415,15 @@ class MyRepositoriesViewSet( permission_classes = [permissions.IsAuthenticated] def get_queryset(self, *args, **kwargs): - return self.queryset.filter(owner=self.request.user) + if self.request.query_params.get('nickname', None): + return self.queryset.filter( + owner__nickname=self.request.query_params.get( + 'nickname', + self.request.user + ) + ) + else: + return self.queryset.filter(owner=self.request.user) class RepositoryViewSet( From d15e7c92c6a5b961d9a53987c4528e8071f14f49 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Mon, 1 Jul 2019 09:18:48 -0300 Subject: [PATCH 021/207] Added lookup_field SearchRepositories --- bothub/api/v1/views.py | 1 + 1 file changed, 1 insertion(+) diff --git a/bothub/api/v1/views.py b/bothub/api/v1/views.py index 0506813a..2551bbf8 100644 --- a/bothub/api/v1/views.py +++ b/bothub/api/v1/views.py @@ -412,6 +412,7 @@ class SearchRepositoriesViewSet( """ queryset = Repository.objects serializer_class = RepositorySerializer + lookup_field = 'nickname' permission_classes = [permissions.IsAuthenticated] def get_queryset(self, *args, **kwargs): From 580fde2dcad9ecc4ab5b2e19c522cbe7874a8b0c Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Mon, 1 Jul 2019 09:38:50 -0300 Subject: [PATCH 022/207] Update Search Repositories queryset error --- bothub/api/v1/views.py | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/bothub/api/v1/views.py b/bothub/api/v1/views.py index 2551bbf8..16bfb987 100644 --- a/bothub/api/v1/views.py +++ b/bothub/api/v1/views.py @@ -413,18 +413,20 @@ class SearchRepositoriesViewSet( queryset = Repository.objects serializer_class = RepositorySerializer lookup_field = 'nickname' - permission_classes = [permissions.IsAuthenticated] def get_queryset(self, *args, **kwargs): - if self.request.query_params.get('nickname', None): - return self.queryset.filter( - owner__nickname=self.request.query_params.get( - 'nickname', - self.request.user + try: + if self.request.query_params.get('nickname', None): + return self.queryset.filter( + owner__nickname=self.request.query_params.get( + 'nickname', + self.request.user + ) ) - ) - else: - return self.queryset.filter(owner=self.request.user) + else: + return self.queryset.filter(owner=self.request.user) + except TypeError: + return self.queryset.none() class RepositoryViewSet( From 477d1157c08756aa8eaf2bc956adc753e5fec2ec Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Mon, 1 Jul 2019 09:52:45 -0300 Subject: [PATCH 023/207] Update test repository Search Repositories --- bothub/api/v1/tests/test_repository.py | 30 +++++++++++++++----------- 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/bothub/api/v1/tests/test_repository.py b/bothub/api/v1/tests/test_repository.py index c7a99afc..5a8b28fe 100644 --- a/bothub/api/v1/tests/test_repository.py +++ b/bothub/api/v1/tests/test_repository.py @@ -17,7 +17,7 @@ from ..views import NewRepositoryViewSet from ..views import RepositoryViewSet -from ..views import MyRepositoriesViewSet +from ..views import SearchRepositoriesViewSet from ..views import RepositoriesViewSet from .utils import create_user_and_token @@ -447,7 +447,7 @@ def test_forbidden(self): status.HTTP_403_FORBIDDEN) -class MyRepositoriesTestCase(TestCase): +class SearchRepositoriesTestCase(TestCase): def setUp(self): self.factory = RequestFactory() @@ -464,20 +464,19 @@ def setUp(self): language=languages.LANGUAGE_EN) self.repository.categories.add(self.category) - def request(self, token): - authorization_header = { - 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), - } + def request(self, nickname): request = self.factory.get( - '/api/my-repositories/', - **authorization_header) - response = MyRepositoriesViewSet.as_view({'get': 'list'})(request) + '/api/search-repositories/?nickname={}'.format(nickname) + ) + response = SearchRepositoriesViewSet.as_view( + {'get': 'list'} + )(request, nickname=nickname) response.render() content_data = json.loads(response.content) return (response, content_data,) def test_okay(self): - response, content_data = self.request(self.owner_token) + response, content_data = self.request('owner') self.assertEqual(response.status_code, 200) self.assertEqual( content_data.get('count'), @@ -486,8 +485,15 @@ def test_okay(self): uuid.UUID(content_data.get('results')[0].get('uuid')), self.repository.uuid) - def test_empty_okay(self): - response, content_data = self.request(self.user_token) + def test_empty_with_user_okay(self): + response, content_data = self.request('fake') + self.assertEqual(response.status_code, 200) + self.assertEqual( + content_data.get('count'), + 0) + + def test_empty_without_user_okay(self): + response, content_data = self.request('') self.assertEqual(response.status_code, 200) self.assertEqual( content_data.get('count'), From 92816553c48ae68ac20ed948fc1efebcb5328f0d Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Tue, 2 Jul 2019 11:18:18 -0300 Subject: [PATCH 024/207] Refact Repository Votes --- bothub/api/v1/serializers/__init__.py | 1 - bothub/api/v1/serializers/repository.py | 9 --- bothub/api/v1/tests/test_repository.py | 94 +------------------------ bothub/api/v1/views.py | 28 -------- bothub/api/v2/repository/serializers.py | 28 +++++++- bothub/api/v2/repository/tests.py | 94 +++++++++++++++++++++++++ bothub/api/v2/repository/views.py | 50 +++++++++++-- bothub/api/v2/routers.py | 3 +- bothub/common/models.py | 25 +++---- 9 files changed, 181 insertions(+), 151 deletions(-) diff --git a/bothub/api/v1/serializers/__init__.py b/bothub/api/v1/serializers/__init__.py index aed2df0d..1e983768 100644 --- a/bothub/api/v1/serializers/__init__.py +++ b/bothub/api/v1/serializers/__init__.py @@ -5,7 +5,6 @@ AnalyzeTextSerializer, EvaluateSerializer, EditRepositorySerializer, - VoteSerializer, RepositoryAuthorizationRoleSerializer, ) diff --git a/bothub/api/v1/serializers/repository.py b/bothub/api/v1/serializers/repository.py index 30fe5c1b..8c37c9e4 100644 --- a/bothub/api/v1/serializers/repository.py +++ b/bothub/api/v1/serializers/repository.py @@ -5,7 +5,6 @@ from bothub.common.models import Repository from bothub.common.models import RepositoryCategory from bothub.common.models import RepositoryAuthorization -from bothub.common.models import RepositoryVote from bothub.common.models import RequestRepositoryAuthorization from bothub.common.languages import LANGUAGE_CHOICES @@ -190,14 +189,6 @@ class EvaluateSerializer(serializers.Serializer): language = serializers.ChoiceField(LANGUAGE_CHOICES, required=True) -class VoteSerializer(serializers.ModelSerializer): - class Meta: - model = RepositoryVote - fields = [ - 'vote', - ] - - class RepositoryAuthorizationRoleSerializer(serializers.ModelSerializer): class Meta: model = RepositoryAuthorization diff --git a/bothub/api/v1/tests/test_repository.py b/bothub/api/v1/tests/test_repository.py index 5a8b28fe..55fcb8e0 100644 --- a/bothub/api/v1/tests/test_repository.py +++ b/bothub/api/v1/tests/test_repository.py @@ -11,7 +11,7 @@ from bothub.common.models import Repository from bothub.common.models import RepositoryExample from bothub.common.models import RepositoryExampleEntity -from bothub.common.models import RepositoryVote +# from bothub.common.models import RepositoryVote from bothub.common.models import RepositoryAuthorization from bothub.common.models import RequestRepositoryAuthorization @@ -765,95 +765,3 @@ def test_none_entities(self): for entity in language_status.get('examples').get('entities'): self.failIfEqual(entity, None) - -class RepositoryVoteTestCase(TestCase): - def setUp(self): - self.factory = RequestFactory() - - self.owner, self.owner_token = create_user_and_token('owner') - self.user, self.user_token = create_user_and_token() - - self.repository = Repository.objects.create( - owner=self.owner, - name='Testing', - slug='test', - language=languages.LANGUAGE_EN) - - def request(self, repository, data={}, token=None): - authorization_header = { - 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), - } if token else {} - request = self.factory.post( - '/api/repository/{}/{}/vote/'.format( - repository.owner.nickname, - repository.slug), - data, - **authorization_header) - response = RepositoryViewSet.as_view( - {'post': 'vote'})(request) - response.render() - content_data = json.loads(response.content) - return (response, content_data,) - - def test_unauthorized(self): - response, content_data = self.request(self.repository) - self.assertEqual( - response.status_code, - status.HTTP_401_UNAUTHORIZED) - - def test_invalid_vote(self): - response, content_data = self.request( - self.repository, - { - 'vote': 2, - }, - self.user_token) - self.assertEqual( - response.status_code, - status.HTTP_400_BAD_REQUEST) - self.assertIn( - 'vote', - content_data.keys()) - - def test_vote_up(self): - response, content_data = self.request( - self.repository, - { - 'vote': RepositoryVote.UP_VOTE, - }, - self.user_token) - self.assertEqual( - response.status_code, - status.HTTP_201_CREATED) - vote = RepositoryVote.objects.get( - repository=self.repository, - user=self.user) - self.assertEqual( - vote.vote, - RepositoryVote.UP_VOTE) - self.assertEqual( - self.repository.votes_sum, - 1) - self.assertEqual( - content_data.get('votes_sum'), - 1) - - def test_vote_down(self): - response, content_data = self.request( - self.repository, - { - 'vote': RepositoryVote.DOWN_VOTE, - }, - self.user_token) - self.assertEqual( - response.status_code, - status.HTTP_201_CREATED) - vote = RepositoryVote.objects.get( - repository=self.repository, - user=self.user) - self.assertEqual( - vote.vote, - RepositoryVote.DOWN_VOTE) - self.assertEqual( - self.repository.votes_sum, - -1) diff --git a/bothub/api/v1/views.py b/bothub/api/v1/views.py index 16bfb987..882097a8 100644 --- a/bothub/api/v1/views.py +++ b/bothub/api/v1/views.py @@ -24,7 +24,6 @@ from bothub.common.models import RepositoryExample from bothub.common.models import RepositoryTranslatedExample from bothub.common.models import RepositoryCategory -from bothub.common.models import RepositoryVote from bothub.common.models import RepositoryAuthorization from bothub.common.models import RequestRepositoryAuthorization from bothub.common.models import RepositoryEntity @@ -48,7 +47,6 @@ from .serializers import EvaluateSerializer from .serializers import EditRepositorySerializer from .serializers import NewRepositoryTranslatedExampleSerializer -from .serializers import VoteSerializer from .serializers import RepositoryAuthorizationRoleSerializer from .serializers import NewRequestRepositoryAuthorizationSerializer from .serializers import RequestRepositoryAuthorizationSerializer @@ -569,32 +567,6 @@ def evaluate(self, request, **kwargs): code=request.status_code) return Response(request.json()) # pragma: no cover - @detail_route( - methods=['POST'], - url_name='repository-vote', - permission_classes=[ - IsAuthenticated, - ]) - def vote(self, request, **kwargs): - user = request.user - repository = self.get_object() - instance, created = RepositoryVote.objects.get_or_create( - user=user, - repository=repository, - defaults={ - 'vote': RepositoryVote.NEUTRAL_VOTE, - }) - serializer = VoteSerializer( - data=request.data, - instance=instance) - serializer.is_valid(raise_exception=True) - serializer.save() - return Response( - { - 'votes_sum': repository.votes_sum, - }, - status=status.HTTP_201_CREATED) - def get_serializer_class(self): if self.request and self.request.method in \ ['OPTIONS'] + WRITE_METHODS or not self.request: diff --git a/bothub/api/v2/repository/serializers.py b/bothub/api/v2/repository/serializers.py index af02e274..444d0a08 100644 --- a/bothub/api/v2/repository/serializers.py +++ b/bothub/api/v2/repository/serializers.py @@ -1,6 +1,6 @@ from rest_framework import serializers -from bothub.common.models import Repository +from bothub.common.models import Repository, RepositoryVote from bothub.common.models import RepositoryCategory from bothub.common.models import RepositoryEntityLabel from bothub.common.models import RepositoryAuthorization @@ -279,3 +279,29 @@ class Meta: def get_absolute_url(self, obj): return obj.get_absolute_url() + + +class RepositoryVotesSerializer(serializers.ModelSerializer): + class Meta: + model = RepositoryVote + fields = [ + 'user', + 'repository', + 'created', + ] + + read_only_fields = [ + 'user', + 'created_at', + ] + + def create(self, validated_data): + user = self.context.get("request").user + repository = validated_data.pop('repository') + vote, created = RepositoryVote.objects.get_or_create( + repository=repository, + user=user + ) + return vote + + diff --git a/bothub/api/v2/repository/tests.py b/bothub/api/v2/repository/tests.py index 85934b2c..2a561c4b 100644 --- a/bothub/api/v2/repository/tests.py +++ b/bothub/api/v2/repository/tests.py @@ -600,3 +600,97 @@ def test_translated_example(self): content_data.get('count'), 0, ) + + + +# class RepositoryVoteTestCase(TestCase): +# def setUp(self): +# self.factory = RequestFactory() +# +# self.owner, self.owner_token = create_user_and_token('owner') +# self.user, self.user_token = create_user_and_token() +# +# self.repository = Repository.objects.create( +# owner=self.owner, +# name='Testing', +# slug='test', +# language=languages.LANGUAGE_EN) +# +# def request(self, repository, data={}, token=None): +# authorization_header = { +# 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), +# } if token else {} +# request = self.factory.post( +# '/api/repository/{}/{}/vote/'.format( +# repository.owner.nickname, +# repository.slug), +# data, +# **authorization_header) +# response = RepositoryViewSet.as_view( +# {'post': 'vote'})(request) +# response.render() +# content_data = json.loads(response.content) +# return (response, content_data,) +# +# def test_unauthorized(self): +# response, content_data = self.request(self.repository) +# self.assertEqual( +# response.status_code, +# status.HTTP_401_UNAUTHORIZED) +# +# def test_invalid_vote(self): +# response, content_data = self.request( +# self.repository, +# { +# 'vote': 2, +# }, +# self.user_token) +# self.assertEqual( +# response.status_code, +# status.HTTP_400_BAD_REQUEST) +# self.assertIn( +# 'vote', +# content_data.keys()) +# +# def test_vote_up(self): +# response, content_data = self.request( +# self.repository, +# { +# 'vote': RepositoryVote.UP_VOTE, +# }, +# self.user_token) +# self.assertEqual( +# response.status_code, +# status.HTTP_201_CREATED) +# vote = RepositoryVote.objects.get( +# repository=self.repository, +# user=self.user) +# self.assertEqual( +# vote.vote, +# RepositoryVote.UP_VOTE) +# self.assertEqual( +# self.repository.votes_sum, +# 1) +# self.assertEqual( +# content_data.get('votes_sum'), +# 1) +# +# def test_vote_down(self): +# response, content_data = self.request( +# self.repository, +# { +# 'vote': RepositoryVote.DOWN_VOTE, +# }, +# self.user_token) +# self.assertEqual( +# response.status_code, +# status.HTTP_201_CREATED) +# vote = RepositoryVote.objects.get( +# repository=self.repository, +# user=self.user) +# self.assertEqual( +# vote.vote, +# RepositoryVote.DOWN_VOTE) +# self.assertEqual( +# self.repository.votes_sum, +# -1) diff --git a/bothub/api/v2/repository/views.py b/bothub/api/v2/repository/views.py index 557b493d..aae52941 100644 --- a/bothub/api/v2/repository/views.py +++ b/bothub/api/v2/repository/views.py @@ -1,13 +1,15 @@ +from rest_framework.response import Response from rest_framework.viewsets import GenericViewSet -from rest_framework import mixins -from rest_framework.permissions import IsAuthenticatedOrReadOnly +from rest_framework import mixins, status +from rest_framework.permissions import IsAuthenticatedOrReadOnly, \ + IsAuthenticated from django_filters.rest_framework import DjangoFilterBackend from rest_framework.filters import SearchFilter -from bothub.common.models import Repository +from bothub.common.models import Repository, RepositoryVote from ..metadata import Metadata -from .serializers import RepositorySerializer +from .serializers import RepositorySerializer, RepositoryVotesSerializer from .serializers import ShortRepositorySerializer from .permissions import RepositoryPermission from .filters import RepositoriesFilter @@ -32,6 +34,46 @@ class RepositoryViewSet( metadata_class = Metadata +class RepositoryVotesViewSet( + mixins.CreateModelMixin, + mixins.DestroyModelMixin, + mixins.ListModelMixin, + GenericViewSet): + """ + Manager repository votes (bot). + """ + queryset = RepositoryVote.objects.all() + lookup_field = 'repository' + lookup_fields = ['user', 'repository'] + serializer_class = RepositoryVotesSerializer + permission_classes = [ + IsAuthenticated + ] + metadata_class = Metadata + + def get_queryset(self, *args, **kwargs): + if self.request.query_params.get('repository', None): + return self.queryset.filter( + repository=self.request.query_params.get( + 'repository', + None + ) + ) + else: + return self.queryset.all() + + def destroy(self, request, *args, **kwargs): + self.queryset.filter( + repository=self.request.query_params.get( + 'repository', + None + ), + user=self.request.user + ).delete() + + return Response(status=status.HTTP_204_NO_CONTENT) + + class RepositoriesViewSet( mixins.ListModelMixin, GenericViewSet): diff --git a/bothub/api/v2/routers.py b/bothub/api/v2/routers.py index 45bfc546..f2f7a327 100644 --- a/bothub/api/v2/routers.py +++ b/bothub/api/v2/routers.py @@ -1,6 +1,6 @@ from rest_framework import routers -from .repository.views import RepositoryViewSet +from .repository.views import RepositoryViewSet, RepositoryVotesViewSet from .repository.views import RepositoriesViewSet from .examples.views import ExamplesViewSet from .evaluate.views import EvaluateViewSet @@ -9,6 +9,7 @@ router = routers.SimpleRouter() router.register('repository', RepositoryViewSet) +router.register('repository-votes', RepositoryVotesViewSet) router.register('repositories', RepositoriesViewSet) router.register('examples', ExamplesViewSet) router.register('evaluate/results', ResultsListViewSet) diff --git a/bothub/common/models.py b/bothub/common/models.py index 6eca13df..8b03e816 100644 --- a/bothub/common/models.py +++ b/bothub/common/models.py @@ -4,6 +4,7 @@ from functools import reduce from django.db import models +from django.utils.datetime_safe import datetime from django.utils.translation import gettext as _ from django.utils import timezone from django.conf import settings @@ -58,10 +59,14 @@ def publics(self): return self.filter(is_private=False) def order_by_relevance(self): + # return self \ + # .annotate(votes_summ=models.Sum('votes__vote')) \ + # .annotate(examples_sum=models.Sum('updates__added')) \ + # .order_by('-votes_summ', '-examples_sum', '-created_at') + return self \ - .annotate(votes_summ=models.Sum('votes__vote')) \ .annotate(examples_sum=models.Sum('updates__added')) \ - .order_by('-votes_summ', '-examples_sum', '-created_at') + .order_by('-examples_sum', '-created_at') def supported_language(self, language): valid_examples = RepositoryExample.objects.filter( @@ -1128,15 +1133,6 @@ def send_new_role_email(self, responsible=None): class RepositoryVote(models.Model): - UP_VOTE = 1 - DOWN_VOTE = -1 - NEUTRAL_VOTE = 0 - VOTE_CHOICES = [ - (UP_VOTE, _('Up'),), - (DOWN_VOTE, _('Down')), - (NEUTRAL_VOTE, _('Neutral')), - ] - class Meta: verbose_name = _('repository vote') verbose_name_plural = _('repository votes') @@ -1153,9 +1149,10 @@ class Meta: Repository, models.CASCADE, related_name='votes') - vote = models.IntegerField( - _('vote'), - choices=VOTE_CHOICES) + created = models.DateTimeField( + editable=False, + default=datetime.now + ) class RequestRepositoryAuthorization(models.Model): From ea4c78a252410c0402d13dc7ec609921ad966742 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Tue, 2 Jul 2019 11:24:46 -0300 Subject: [PATCH 025/207] Repository vote migration --- .../migrations/0032_auto_20190702_1419.py | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 bothub/common/migrations/0032_auto_20190702_1419.py diff --git a/bothub/common/migrations/0032_auto_20190702_1419.py b/bothub/common/migrations/0032_auto_20190702_1419.py new file mode 100644 index 00000000..a1d0a178 --- /dev/null +++ b/bothub/common/migrations/0032_auto_20190702_1419.py @@ -0,0 +1,23 @@ +# Generated by Django 2.1.5 on 2019-07-02 14:19 + +from django.db import migrations, models +import django.utils.datetime_safe + + +class Migration(migrations.Migration): + + dependencies = [ + ('common', '0031_auto_20190502_1732'), + ] + + operations = [ + migrations.RemoveField( + model_name='repositoryvote', + name='vote', + ), + migrations.AddField( + model_name='repositoryvote', + name='created', + field=models.DateTimeField(default=django.utils.datetime_safe.datetime.now, editable=False), + ), + ] From bbc75f465236308d637af5f1c0f7cdd63115e4f5 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Tue, 2 Jul 2019 11:48:13 -0300 Subject: [PATCH 026/207] Refact Repository vote --- bothub/api/v1/tests/test_repository.py | 1 - bothub/api/v2/repository/serializers.py | 5 +++-- bothub/api/v2/repository/views.py | 7 ++++--- bothub/api/v2/routers.py | 3 ++- .../migrations/0033_auto_20190702_1443.py | 18 ++++++++++++++++++ bothub/common/models.py | 8 +------- 6 files changed, 28 insertions(+), 14 deletions(-) create mode 100644 bothub/common/migrations/0033_auto_20190702_1443.py diff --git a/bothub/api/v1/tests/test_repository.py b/bothub/api/v1/tests/test_repository.py index 55fcb8e0..656837f0 100644 --- a/bothub/api/v1/tests/test_repository.py +++ b/bothub/api/v1/tests/test_repository.py @@ -11,7 +11,6 @@ from bothub.common.models import Repository from bothub.common.models import RepositoryExample from bothub.common.models import RepositoryExampleEntity -# from bothub.common.models import RepositoryVote from bothub.common.models import RepositoryAuthorization from bothub.common.models import RequestRepositoryAuthorization diff --git a/bothub/api/v2/repository/serializers.py b/bothub/api/v2/repository/serializers.py index 444d0a08..29dc81b7 100644 --- a/bothub/api/v2/repository/serializers.py +++ b/bothub/api/v2/repository/serializers.py @@ -1,6 +1,7 @@ from rest_framework import serializers -from bothub.common.models import Repository, RepositoryVote +from bothub.common.models import Repository +from bothub.common.models import RepositoryVote from bothub.common.models import RepositoryCategory from bothub.common.models import RepositoryEntityLabel from bothub.common.models import RepositoryAuthorization @@ -296,7 +297,7 @@ class Meta: ] def create(self, validated_data): - user = self.context.get("request").user + user = self.context.get('request').user repository = validated_data.pop('repository') vote, created = RepositoryVote.objects.get_or_create( repository=repository, diff --git a/bothub/api/v2/repository/views.py b/bothub/api/v2/repository/views.py index aae52941..ab6ef167 100644 --- a/bothub/api/v2/repository/views.py +++ b/bothub/api/v2/repository/views.py @@ -1,15 +1,16 @@ from rest_framework.response import Response from rest_framework.viewsets import GenericViewSet from rest_framework import mixins, status -from rest_framework.permissions import IsAuthenticatedOrReadOnly, \ - IsAuthenticated +from rest_framework.permissions import IsAuthenticatedOrReadOnly +from rest_framework.permissions import IsAuthenticated from django_filters.rest_framework import DjangoFilterBackend from rest_framework.filters import SearchFilter from bothub.common.models import Repository, RepositoryVote from ..metadata import Metadata -from .serializers import RepositorySerializer, RepositoryVotesSerializer +from .serializers import RepositorySerializer +from .serializers import RepositoryVotesSerializer from .serializers import ShortRepositorySerializer from .permissions import RepositoryPermission from .filters import RepositoriesFilter diff --git a/bothub/api/v2/routers.py b/bothub/api/v2/routers.py index f2f7a327..805ca5c6 100644 --- a/bothub/api/v2/routers.py +++ b/bothub/api/v2/routers.py @@ -1,6 +1,7 @@ from rest_framework import routers -from .repository.views import RepositoryViewSet, RepositoryVotesViewSet +from .repository.views import RepositoryViewSet +from .repository.views import RepositoryVotesViewSet from .repository.views import RepositoriesViewSet from .examples.views import ExamplesViewSet from .evaluate.views import EvaluateViewSet diff --git a/bothub/common/migrations/0033_auto_20190702_1443.py b/bothub/common/migrations/0033_auto_20190702_1443.py new file mode 100644 index 00000000..1d969c29 --- /dev/null +++ b/bothub/common/migrations/0033_auto_20190702_1443.py @@ -0,0 +1,18 @@ +# Generated by Django 2.1.5 on 2019-07-02 14:43 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('common', '0032_auto_20190702_1419'), + ] + + operations = [ + migrations.AlterField( + model_name='repositoryvote', + name='created', + field=models.DateTimeField(auto_now_add=True), + ), + ] diff --git a/bothub/common/models.py b/bothub/common/models.py index 8b03e816..1a4e398f 100644 --- a/bothub/common/models.py +++ b/bothub/common/models.py @@ -4,7 +4,6 @@ from functools import reduce from django.db import models -from django.utils.datetime_safe import datetime from django.utils.translation import gettext as _ from django.utils import timezone from django.conf import settings @@ -59,11 +58,6 @@ def publics(self): return self.filter(is_private=False) def order_by_relevance(self): - # return self \ - # .annotate(votes_summ=models.Sum('votes__vote')) \ - # .annotate(examples_sum=models.Sum('updates__added')) \ - # .order_by('-votes_summ', '-examples_sum', '-created_at') - return self \ .annotate(examples_sum=models.Sum('updates__added')) \ .order_by('-examples_sum', '-created_at') @@ -1151,7 +1145,7 @@ class Meta: related_name='votes') created = models.DateTimeField( editable=False, - default=datetime.now + auto_now_add=True ) From cedc6ab653b29bac7bc4e1d678e48d7a9f810553 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Tue, 2 Jul 2019 12:02:13 -0300 Subject: [PATCH 027/207] Added test list Repository Votes --- bothub/api/v2/repository/tests.py | 138 ++++++++++-------------------- 1 file changed, 46 insertions(+), 92 deletions(-) diff --git a/bothub/api/v2/repository/tests.py b/bothub/api/v2/repository/tests.py index 2a561c4b..e37467bb 100644 --- a/bothub/api/v2/repository/tests.py +++ b/bothub/api/v2/repository/tests.py @@ -5,7 +5,7 @@ from django.test.client import MULTIPART_CONTENT from rest_framework import status -from bothub.common.models import RepositoryCategory +from bothub.common.models import RepositoryCategory, RepositoryVote from bothub.common.models import Repository from bothub.common.models import RequestRepositoryAuthorization from bothub.common.models import RepositoryExample @@ -16,6 +16,7 @@ from .views import RepositoryViewSet from .views import RepositoriesViewSet +from .views import RepositoryVotesViewSet from .serializers import RepositorySerializer @@ -603,94 +604,47 @@ def test_translated_example(self): -# class RepositoryVoteTestCase(TestCase): -# def setUp(self): -# self.factory = RequestFactory() -# -# self.owner, self.owner_token = create_user_and_token('owner') -# self.user, self.user_token = create_user_and_token() -# -# self.repository = Repository.objects.create( -# owner=self.owner, -# name='Testing', -# slug='test', -# language=languages.LANGUAGE_EN) -# -# def request(self, repository, data={}, token=None): -# authorization_header = { -# 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), -# } if token else {} -# request = self.factory.post( -# '/api/repository/{}/{}/vote/'.format( -# repository.owner.nickname, -# repository.slug), -# data, -# **authorization_header) -# response = RepositoryViewSet.as_view( -# {'post': 'vote'})(request) -# response.render() -# content_data = json.loads(response.content) -# return (response, content_data,) -# -# def test_unauthorized(self): -# response, content_data = self.request(self.repository) -# self.assertEqual( -# response.status_code, -# status.HTTP_401_UNAUTHORIZED) -# -# def test_invalid_vote(self): -# response, content_data = self.request( -# self.repository, -# { -# 'vote': 2, -# }, -# self.user_token) -# self.assertEqual( -# response.status_code, -# status.HTTP_400_BAD_REQUEST) -# self.assertIn( -# 'vote', -# content_data.keys()) -# -# def test_vote_up(self): -# response, content_data = self.request( -# self.repository, -# { -# 'vote': RepositoryVote.UP_VOTE, -# }, -# self.user_token) -# self.assertEqual( -# response.status_code, -# status.HTTP_201_CREATED) -# vote = RepositoryVote.objects.get( -# repository=self.repository, -# user=self.user) -# self.assertEqual( -# vote.vote, -# RepositoryVote.UP_VOTE) -# self.assertEqual( -# self.repository.votes_sum, -# 1) -# self.assertEqual( -# content_data.get('votes_sum'), -# 1) -# -# def test_vote_down(self): -# response, content_data = self.request( -# self.repository, -# { -# 'vote': RepositoryVote.DOWN_VOTE, -# }, -# self.user_token) -# self.assertEqual( -# response.status_code, -# status.HTTP_201_CREATED) -# vote = RepositoryVote.objects.get( -# repository=self.repository, -# user=self.user) -# self.assertEqual( -# vote.vote, -# RepositoryVote.DOWN_VOTE) -# self.assertEqual( -# self.repository.votes_sum, -# -1) +class ListRepositoryVoteTestCase(TestCase): + def setUp(self): + self.factory = RequestFactory() + + self.owner, self.owner_token = create_user_and_token('owner') + self.user, self.token = create_user_and_token() + + self.repository = Repository.objects.create( + owner=self.owner, + name='Testing', + slug='test', + language=languages.LANGUAGE_EN + ) + + self.repository_votes = RepositoryVote.objects.create( + user=self.owner, + repository=self.repository + ) + + def request(self, token): + authorization_header = { + 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), + } + request = self.factory.get( + '/api/v2/repository-votes/?repository={}'.format( + self.repository.uuid + ), **authorization_header + ) + response = RepositoryVotesViewSet.as_view({'get': 'list'})( + request, + repository=self.repository.uuid + ) + response.render() + content_data = json.loads(response.content) + return (response, content_data,) + + def test_okay(self): + response, content_data = self.request(self.owner_token) + + self.assertEqual(content_data['count'], 1) + self.assertEqual(len(content_data['results']), 1) + self.assertEqual( + response.status_code, + status.HTTP_200_OK) From b559c3362b865e3e273c983b9b1e6e2e894eb61c Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Wed, 3 Jul 2019 08:47:26 -0300 Subject: [PATCH 028/207] Added test New Repository Votes and Destroy Repository Votes --- bothub/api/v2/repository/tests.py | 121 +++++++++++++++++++++++++++++- 1 file changed, 118 insertions(+), 3 deletions(-) diff --git a/bothub/api/v2/repository/tests.py b/bothub/api/v2/repository/tests.py index e37467bb..29764185 100644 --- a/bothub/api/v2/repository/tests.py +++ b/bothub/api/v2/repository/tests.py @@ -603,7 +603,6 @@ def test_translated_example(self): ) - class ListRepositoryVoteTestCase(TestCase): def setUp(self): self.factory = RequestFactory() @@ -625,7 +624,7 @@ def setUp(self): def request(self, token): authorization_header = { - 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), + 'HTTP_AUTHORIZATION': 'Token {}'.format(token), } request = self.factory.get( '/api/v2/repository-votes/?repository={}'.format( @@ -641,10 +640,126 @@ def request(self, token): return (response, content_data,) def test_okay(self): - response, content_data = self.request(self.owner_token) + response, content_data = self.request(self.owner_token.key) self.assertEqual(content_data['count'], 1) self.assertEqual(len(content_data['results']), 1) self.assertEqual( response.status_code, status.HTTP_200_OK) + + def test_private_okay(self): + response, content_data = self.request('') + self.assertEqual( + response.status_code, + status.HTTP_401_UNAUTHORIZED) + + +class NewRepositoryVoteTestCase(TestCase): + def setUp(self): + self.factory = RequestFactory() + + self.owner, self.owner_token = create_user_and_token('owner') + self.user, self.token = create_user_and_token() + + self.repository = Repository.objects.create( + owner=self.owner, + name='Testing', + slug='test', + language=languages.LANGUAGE_EN + ) + + def request(self, data, token): + authorization_header = { + 'HTTP_AUTHORIZATION': 'Token {}'.format(token), + } + request = self.factory.post( + '/api/v2/repository-votes/', + json.dumps(data), + content_type='application/json', + **authorization_header + ) + response = RepositoryVotesViewSet.as_view({'post': 'create'})( + request, + repository=self.repository.uuid + ) + response.render() + content_data = json.loads(response.content) + return (response, content_data,) + + def test_okay(self): + response, content_data = self.request( + { + 'repository': str(self.repository.uuid) + }, self.owner_token.key) + + self.assertEqual(content_data['user'], 1) + self.assertEqual( + content_data['repository'], + str(self.repository.uuid) + ) + self.assertEqual( + response.status_code, + status.HTTP_201_CREATED + ) + + def test_private_okay(self): + response, content_data = self.request( + { + 'repository': str(self.repository.uuid) + }, '') + + self.assertEqual( + response.status_code, + status.HTTP_401_UNAUTHORIZED + ) + + +class DestroyRepositoryVoteTestCase(TestCase): + def setUp(self): + self.factory = RequestFactory() + + self.owner, self.owner_token = create_user_and_token('owner') + self.user, self.token = create_user_and_token() + + self.repository = Repository.objects.create( + owner=self.owner, + name='Testing', + slug='test', + language=languages.LANGUAGE_EN + ) + + self.repository_votes = RepositoryVote.objects.create( + user=self.owner, + repository=self.repository + ) + + def request(self, token): + authorization_header = { + 'HTTP_AUTHORIZATION': 'Token {}'.format(token), + } + request = self.factory.delete( + '/api/v2/repository-votes/{}/'.format(str(self.repository.uuid)), + **authorization_header + ) + response = RepositoryVotesViewSet.as_view({'delete': 'destroy'})( + request, + repository=self.repository.uuid + ) + response.render() + return response + + def test_okay(self): + response = self.request(self.owner_token.key) + self.assertEqual( + response.status_code, + status.HTTP_204_NO_CONTENT + ) + + def test_private_okay(self): + response = self.request('') + + self.assertEqual( + response.status_code, + status.HTTP_401_UNAUTHORIZED + ) From 700ccf14f2cdeacb54a0ab82fad3b09980267b86 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Wed, 3 Jul 2019 08:55:46 -0300 Subject: [PATCH 029/207] Remove old Repository Votes --- bothub/api/v1/serializers/repository.py | 1 - bothub/common/models.py | 5 ----- 2 files changed, 6 deletions(-) diff --git a/bothub/api/v1/serializers/repository.py b/bothub/api/v1/serializers/repository.py index 8c37c9e4..ac8ad754 100644 --- a/bothub/api/v1/serializers/repository.py +++ b/bothub/api/v1/serializers/repository.py @@ -84,7 +84,6 @@ class Meta: 'requirements_to_train', 'languages_ready_for_train', 'languages_warnings', - 'votes_sum', 'created_at', ] diff --git a/bothub/common/models.py b/bothub/common/models.py index 1a4e398f..b19d3dfb 100644 --- a/bothub/common/models.py +++ b/bothub/common/models.py @@ -273,11 +273,6 @@ def languages_warnings(self): lambda u: (u.language, u.warnings,), self.current_updates))) - @property - def votes_sum(self): - return self.votes.aggregate( - votes_sum=models.Sum('vote')).get('votes_sum') - @property def intents(self): return list(set(self.examples( From 21a1059301931564ee24a57d024aaa9694ca60a2 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Wed, 3 Jul 2019 09:09:04 -0300 Subject: [PATCH 030/207] Change directory tests v2 --- .../{examples/tests.py => tests/test_examples.py} | 4 ++-- .../tests.py => tests/test_repository.py} | 13 ++++++------- 2 files changed, 8 insertions(+), 9 deletions(-) rename bothub/api/v2/{examples/tests.py => tests/test_examples.py} (98%) rename bothub/api/v2/{repository/tests.py => tests/test_repository.py} (98%) diff --git a/bothub/api/v2/examples/tests.py b/bothub/api/v2/tests/test_examples.py similarity index 98% rename from bothub/api/v2/examples/tests.py rename to bothub/api/v2/tests/test_examples.py index c1ffd072..84b4b758 100644 --- a/bothub/api/v2/examples/tests.py +++ b/bothub/api/v2/tests/test_examples.py @@ -10,8 +10,8 @@ from bothub.common.models import RepositoryExampleEntity from bothub.common import languages -from ..tests.utils import create_user_and_token -from .views import ExamplesViewSet +from bothub.api.v2.tests.utils import create_user_and_token +from bothub.api.v2.examples.views import ExamplesViewSet class ListExamplesAPITestCase(TestCase): diff --git a/bothub/api/v2/repository/tests.py b/bothub/api/v2/tests/test_repository.py similarity index 98% rename from bothub/api/v2/repository/tests.py rename to bothub/api/v2/tests/test_repository.py index 29764185..fa0c51c7 100644 --- a/bothub/api/v2/repository/tests.py +++ b/bothub/api/v2/tests/test_repository.py @@ -12,12 +12,12 @@ from bothub.common.models import RepositoryTranslatedExample from bothub.common import languages -from ..tests.utils import create_user_and_token +from bothub.api.v2.tests.utils import create_user_and_token -from .views import RepositoryViewSet -from .views import RepositoriesViewSet -from .views import RepositoryVotesViewSet -from .serializers import RepositorySerializer +from bothub.api.v2.repository.views import RepositoryViewSet +from bothub.api.v2.repository.views import RepositoriesViewSet +from bothub.api.v2.repository.views import RepositoryVotesViewSet +from bothub.api.v2.repository.serializers import RepositorySerializer def get_valid_mockups(categories): @@ -692,8 +692,7 @@ def test_okay(self): { 'repository': str(self.repository.uuid) }, self.owner_token.key) - - self.assertEqual(content_data['user'], 1) + self.assertEqual(content_data['user'], self.owner.id) self.assertEqual( content_data['repository'], str(self.repository.uuid) From a5897cf2a3cfa07855bbfa926d463f9b466562d6 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Wed, 3 Jul 2019 10:07:53 -0300 Subject: [PATCH 031/207] Update permission repository votes --- bothub/api/v2/repository/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bothub/api/v2/repository/views.py b/bothub/api/v2/repository/views.py index ab6ef167..cc335289 100644 --- a/bothub/api/v2/repository/views.py +++ b/bothub/api/v2/repository/views.py @@ -48,7 +48,7 @@ class RepositoryVotesViewSet( lookup_fields = ['user', 'repository'] serializer_class = RepositoryVotesSerializer permission_classes = [ - IsAuthenticated + IsAuthenticatedOrReadOnly ] metadata_class = Metadata From d8ab025d0ca284da3bd5bfacc454e4cb9d7a10db Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Wed, 3 Jul 2019 10:46:25 -0300 Subject: [PATCH 032/207] Added Repository Votes search by nickname --- bothub/api/v2/repository/views.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/bothub/api/v2/repository/views.py b/bothub/api/v2/repository/views.py index cc335289..a490d85c 100644 --- a/bothub/api/v2/repository/views.py +++ b/bothub/api/v2/repository/views.py @@ -60,6 +60,13 @@ def get_queryset(self, *args, **kwargs): None ) ) + elif self.request.query_params.get('user', None): + return self.queryset.filter( + user__nickname=self.request.query_params.get( + 'user', + None + ) + ) else: return self.queryset.all() From b3e42a3ace2d39f1dabbe1ba072a7ed386220aa6 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Wed, 3 Jul 2019 10:46:48 -0300 Subject: [PATCH 033/207] Added test check search by nickname Repository Votes --- bothub/api/v2/tests/test_repository.py | 46 ++++++++++++++++++++++---- 1 file changed, 39 insertions(+), 7 deletions(-) diff --git a/bothub/api/v2/tests/test_repository.py b/bothub/api/v2/tests/test_repository.py index fa0c51c7..4091631f 100644 --- a/bothub/api/v2/tests/test_repository.py +++ b/bothub/api/v2/tests/test_repository.py @@ -622,13 +622,14 @@ def setUp(self): repository=self.repository ) - def request(self, token): + def request(self, param, value, token): authorization_header = { 'HTTP_AUTHORIZATION': 'Token {}'.format(token), } request = self.factory.get( - '/api/v2/repository-votes/?repository={}'.format( - self.repository.uuid + '/api/v2/repository-votes/?{}={}'.format( + param, + value ), **authorization_header ) response = RepositoryVotesViewSet.as_view({'get': 'list'})( @@ -639,8 +640,12 @@ def request(self, token): content_data = json.loads(response.content) return (response, content_data,) - def test_okay(self): - response, content_data = self.request(self.owner_token.key) + def test_repository_okay(self): + response, content_data = self.request( + 'repository', + self.repository.uuid, + self.owner_token.key + ) self.assertEqual(content_data['count'], 1) self.assertEqual(len(content_data['results']), 1) @@ -648,8 +653,35 @@ def test_okay(self): response.status_code, status.HTTP_200_OK) - def test_private_okay(self): - response, content_data = self.request('') + def test_private_repository_okay(self): + response, content_data = self.request( + 'repository', + self.repository.uuid, + '' + ) + self.assertEqual( + response.status_code, + status.HTTP_401_UNAUTHORIZED) + + def test_user_okay(self): + response, content_data = self.request( + 'user', + self.owner.nickname, + self.owner_token.key + ) + + self.assertEqual(content_data['count'], 1) + self.assertEqual(len(content_data['results']), 1) + self.assertEqual( + response.status_code, + status.HTTP_200_OK) + + def test_private_user_okay(self): + response, content_data = self.request( + 'user', + self.owner.nickname, + '' + ) self.assertEqual( response.status_code, status.HTTP_401_UNAUTHORIZED) From fa74f09551c88dcef29c0d175b4d691f8b4fa0f0 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Thu, 4 Jul 2019 08:30:07 -0300 Subject: [PATCH 034/207] Added router repositories contributions --- bothub/api/v2/repository/serializers.py | 15 ++++++++++++ bothub/api/v2/repository/views.py | 31 +++++++++++++++++++++++-- bothub/api/v2/routers.py | 2 ++ 3 files changed, 46 insertions(+), 2 deletions(-) diff --git a/bothub/api/v2/repository/serializers.py b/bothub/api/v2/repository/serializers.py index 29dc81b7..cf6fa99b 100644 --- a/bothub/api/v2/repository/serializers.py +++ b/bothub/api/v2/repository/serializers.py @@ -306,3 +306,18 @@ def create(self, validated_data): return vote +class RepositoryContributionsSerializer(serializers.ModelSerializer): + class Meta: + model = RepositoryAuthorization + fields = [ + 'user', + 'repository', + 'role', + 'created_at', + ] + + read_only_fields = [ + 'user', + 'role', + 'created_at', + ] diff --git a/bothub/api/v2/repository/views.py b/bothub/api/v2/repository/views.py index a490d85c..3f7bd691 100644 --- a/bothub/api/v2/repository/views.py +++ b/bothub/api/v2/repository/views.py @@ -2,14 +2,16 @@ from rest_framework.viewsets import GenericViewSet from rest_framework import mixins, status from rest_framework.permissions import IsAuthenticatedOrReadOnly -from rest_framework.permissions import IsAuthenticated from django_filters.rest_framework import DjangoFilterBackend from rest_framework.filters import SearchFilter -from bothub.common.models import Repository, RepositoryVote +from bothub.common.models import Repository +from bothub.common.models import RepositoryVote +from bothub.common.models import RepositoryAuthorization from ..metadata import Metadata from .serializers import RepositorySerializer +from .serializers import RepositoryContributionsSerializer from .serializers import RepositoryVotesSerializer from .serializers import ShortRepositorySerializer from .permissions import RepositoryPermission @@ -100,3 +102,28 @@ class RepositoriesViewSet( '^name', '=name', ] + + +class RepositoriesContributionsViewSet( + mixins.ListModelMixin, + GenericViewSet): + """ + List Repositories Contributions by user, ?nickname=nickname. + """ + serializer_class = RepositoryContributionsSerializer + queryset = RepositoryAuthorization.objects.all() + permission_classes = [ + IsAuthenticatedOrReadOnly + ] + lookup_field = 'nickname' + + def get_queryset(self): + if self.request.query_params.get('nickname', None): + return self.queryset.filter( + user__nickname=self.request.query_params.get( + 'nickname', + None + ) + ) + else: + return self.queryset.none() diff --git a/bothub/api/v2/routers.py b/bothub/api/v2/routers.py index 805ca5c6..680ee2c7 100644 --- a/bothub/api/v2/routers.py +++ b/bothub/api/v2/routers.py @@ -3,6 +3,7 @@ from .repository.views import RepositoryViewSet from .repository.views import RepositoryVotesViewSet from .repository.views import RepositoriesViewSet +from .repository.views import RepositoriesContributionsViewSet from .examples.views import ExamplesViewSet from .evaluate.views import EvaluateViewSet from .evaluate.views import ResultsListViewSet @@ -12,6 +13,7 @@ router.register('repository', RepositoryViewSet) router.register('repository-votes', RepositoryVotesViewSet) router.register('repositories', RepositoriesViewSet) +router.register('repositories-contributions', RepositoriesContributionsViewSet) router.register('examples', ExamplesViewSet) router.register('evaluate/results', ResultsListViewSet) router.register('evaluate', EvaluateViewSet) From 2d891c19e19d39e656b5ec7fafeacc16cf0db954 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Thu, 4 Jul 2019 08:49:14 -0300 Subject: [PATCH 035/207] Added test repository contributions --- bothub/api/v2/tests/test_repository.py | 65 +++++++++++++++++++++++++- 1 file changed, 64 insertions(+), 1 deletion(-) diff --git a/bothub/api/v2/tests/test_repository.py b/bothub/api/v2/tests/test_repository.py index 4091631f..31eac819 100644 --- a/bothub/api/v2/tests/test_repository.py +++ b/bothub/api/v2/tests/test_repository.py @@ -5,7 +5,9 @@ from django.test.client import MULTIPART_CONTENT from rest_framework import status -from bothub.common.models import RepositoryCategory, RepositoryVote +from bothub.common.models import RepositoryCategory +from bothub.common.models import RepositoryVote +from bothub.common.models import RepositoryAuthorization from bothub.common.models import Repository from bothub.common.models import RequestRepositoryAuthorization from bothub.common.models import RepositoryExample @@ -15,6 +17,7 @@ from bothub.api.v2.tests.utils import create_user_and_token from bothub.api.v2.repository.views import RepositoryViewSet +from bothub.api.v2.repository.views import RepositoriesContributionsViewSet from bothub.api.v2.repository.views import RepositoriesViewSet from bothub.api.v2.repository.views import RepositoryVotesViewSet from bothub.api.v2.repository.serializers import RepositorySerializer @@ -794,3 +797,63 @@ def test_private_okay(self): response.status_code, status.HTTP_401_UNAUTHORIZED ) + + +class ListRepositoryContributionsTestCase(TestCase): + def setUp(self): + self.factory = RequestFactory() + + self.owner, self.owner_token = create_user_and_token('owner') + self.user, self.token = create_user_and_token() + + self.repository = Repository.objects.create( + owner=self.owner, + name='Testing', + slug='test', + language=languages.LANGUAGE_EN + ) + + text = 'I can contribute' + self.repository_request_auth = \ + RequestRepositoryAuthorization.objects.create( + user=self.user, + repository=self.repository, + approved_by=self.owner, + text=text + ) + + self.repository_auth = RepositoryAuthorization.objects.create( + user=self.user, + repository=self.repository, + role=0 + ) + + def request(self): + request = self.factory.get( + '/api/v2/repositories-contributions/?nickname={}'.format( + self.user.nickname + ) + ) + response = RepositoriesContributionsViewSet.as_view({'get': 'list'})( + request, + nickname=self.user.nickname + ) + response.render() + content_data = json.loads(response.content) + return (response, content_data,) + + def test_okay(self): + response, content_data = self.request() + self.assertEqual( + response.status_code, + status.HTTP_200_OK + ) + self.assertEqual( + content_data['count'], + 1 + ) + self.assertEqual( + len(content_data['results']), + 1 + ) + From 35fd36c171223d003f1a94b8a3a51279bb7a71db Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Thu, 4 Jul 2019 09:13:26 -0300 Subject: [PATCH 036/207] Update decorator deprecated DRF 3.8 --- bothub/api/v1/routers.py | 4 ++-- bothub/api/v1/views.py | 17 +++++++++++------ 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/bothub/api/v1/routers.py b/bothub/api/v1/routers.py index ec708a61..d33a0e16 100644 --- a/bothub/api/v1/routers.py +++ b/bothub/api/v1/routers.py @@ -31,7 +31,7 @@ class Router(routers.SimpleRouter): routes = [ # Dynamically generated list routes. - # Generated using @list_route decorator + # Generated using @action decorator # on methods of the viewset. routers.DynamicRoute( url=r'^{prefix}/{url_path}{trailing_slash}$', @@ -40,7 +40,7 @@ class Router(routers.SimpleRouter): initkwargs={}, ), # Dynamically generated detail routes. - # Generated using @detail_route decorator on methods of the viewset. + # Generated using @action decorator on methods of the viewset. routers.DynamicRoute( url=r'^{prefix}/{lookup}/{url_path}{trailing_slash}$', name='{basename}-{url_name}', diff --git a/bothub/api/v1/views.py b/bothub/api/v1/views.py index 882097a8..1e9737ee 100644 --- a/bothub/api/v1/views.py +++ b/bothub/api/v1/views.py @@ -1,7 +1,7 @@ from rest_framework.viewsets import GenericViewSet from rest_framework import mixins from rest_framework import permissions -from rest_framework.decorators import detail_route +from rest_framework.decorators import action from rest_framework.response import Response from rest_framework.exceptions import APIException from rest_framework.exceptions import NotFound @@ -457,7 +457,8 @@ class RepositoryViewSet( RepositoryPermission, ] - @detail_route( + @action( + detail=True, methods=['GET'], url_name='repository-languages-status') def languagesstatus(self, request, **kwargs): @@ -469,7 +470,8 @@ def languagesstatus(self, request, **kwargs): 'languages_status': repository.languages_status, }) - @detail_route( + @action( + detail=True, methods=['GET'], url_name='repository-authorization') def authorization(self, request, **kwargs): @@ -483,7 +485,8 @@ def authorization(self, request, **kwargs): serializer = RepositoryAuthorizationSerializer(user_authorization) return Response(serializer.data) - @detail_route( + @action( + detail=True, methods=['GET'], url_name='repository-train') def train(self, request, **kwargs): @@ -502,7 +505,8 @@ def train(self, request, **kwargs): code=request.status_code) return Response(request.json()) # pragma: no cover - @detail_route( + @action( + detail=True, methods=['POST'], url_name='repository-analyze', permission_classes=[]) @@ -533,7 +537,8 @@ def analyze(self, request, **kwargs): message = error.get('message') # pragma: no cover raise APIException(detail=message) # pragma: no cover - @detail_route( + @action( + detail=True, methods=['POST'], url_name='repository-evaluate') def evaluate(self, request, **kwargs): From 70e9c9070b55777a472228bc2f1a580b3cf1d27d Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Thu, 4 Jul 2019 09:27:22 -0300 Subject: [PATCH 037/207] [fix] Travis --- bothub/api/v1/tests/test_repository.py | 1 - bothub/api/v2/tests/test_repository.py | 1 - 2 files changed, 2 deletions(-) diff --git a/bothub/api/v1/tests/test_repository.py b/bothub/api/v1/tests/test_repository.py index 656837f0..7194c993 100644 --- a/bothub/api/v1/tests/test_repository.py +++ b/bothub/api/v1/tests/test_repository.py @@ -763,4 +763,3 @@ def test_none_entities(self): language_status = languages_status.get(language) for entity in language_status.get('examples').get('entities'): self.failIfEqual(entity, None) - diff --git a/bothub/api/v2/tests/test_repository.py b/bothub/api/v2/tests/test_repository.py index 31eac819..19d6cb3f 100644 --- a/bothub/api/v2/tests/test_repository.py +++ b/bothub/api/v2/tests/test_repository.py @@ -856,4 +856,3 @@ def test_okay(self): len(content_data['results']), 1 ) - From 10e87658cc91f40e5e1d179363d2531389d7a846 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Thu, 4 Jul 2019 09:39:42 -0300 Subject: [PATCH 038/207] [fix] PEP8 --- bothub/api/v2/evaluate/views.py | 6 +++--- bothub/api/v2/tests/test_evaluate.py | 16 +++++++++------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/bothub/api/v2/evaluate/views.py b/bothub/api/v2/evaluate/views.py index c36cf1c6..6977729b 100644 --- a/bothub/api/v2/evaluate/views.py +++ b/bothub/api/v2/evaluate/views.py @@ -1,7 +1,7 @@ from rest_framework.viewsets import GenericViewSet from rest_framework import mixins -from rest_framework.permissions import \ - IsAuthenticatedOrReadOnly, IsAuthenticated +from rest_framework.permissions import IsAuthenticatedOrReadOnly +from rest_framework.permissions import IsAuthenticated from rest_framework.filters import SearchFilter from rest_framework.filters import OrderingFilter @@ -67,7 +67,7 @@ class ResultsListViewSet( GenericViewSet): queryset = RepositoryEvaluateResult.objects - lookup_fields = ('repository_uuid',) + lookup_fields = ['repository_uuid'] serializer_class = RepositoryEvaluateResultVersionsSerializer permission_classes = [ IsAuthenticated, diff --git a/bothub/api/v2/tests/test_evaluate.py b/bothub/api/v2/tests/test_evaluate.py index 470b9d27..850dfcb7 100644 --- a/bothub/api/v2/tests/test_evaluate.py +++ b/bothub/api/v2/tests/test_evaluate.py @@ -1,16 +1,18 @@ -import json - from django.test import RequestFactory from django.test import TestCase from rest_framework import status - from bothub.api.v2.evaluate.views import EvaluateViewSet, ResultsListViewSet from bothub.common import languages -from bothub.common.models import RepositoryExample, RepositoryUpdate, \ - Repository, RepositoryEvaluate, RepositoryEvaluateResultScore, \ - RepositoryEvaluateResult, RepositoryEvaluateResultIntent, \ - RepositoryEvaluateResultEntity +from bothub.common.models import RepositoryExample +from bothub.common.models import RepositoryUpdate +from bothub.common.models import Repository +from bothub.common.models import RepositoryEvaluate +from bothub.common.models import RepositoryEvaluateResultScore +from bothub.common.models import RepositoryEvaluateResult +from bothub.common.models import RepositoryEvaluateResultIntent +from bothub.common.models import RepositoryEvaluateResultEntity from .utils import create_user_and_token +import json # TestCases From 93b84970c0c39e6637140e77538c53a84e950f29 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Thu, 4 Jul 2019 09:57:34 -0300 Subject: [PATCH 039/207] Update import test --- bothub/api/v2/tests/test_evaluate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bothub/api/v2/tests/test_evaluate.py b/bothub/api/v2/tests/test_evaluate.py index 850dfcb7..6d7c7dc9 100644 --- a/bothub/api/v2/tests/test_evaluate.py +++ b/bothub/api/v2/tests/test_evaluate.py @@ -1,3 +1,4 @@ +import json from django.test import RequestFactory from django.test import TestCase from rest_framework import status @@ -12,7 +13,6 @@ from bothub.common.models import RepositoryEvaluateResultIntent from bothub.common.models import RepositoryEvaluateResultEntity from .utils import create_user_and_token -import json # TestCases From 335d0d4caba652b3364ec36a361fa2a8f42a0022 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Tue, 9 Jul 2019 14:12:46 -0300 Subject: [PATCH 040/207] Added support swagger doc --- Pipfile | 1 + Pipfile.lock | 87 ++++++++++++++++++++++++++++++---------------- bothub/settings.py | 28 +++++++++++++++ bothub/urls.py | 2 ++ 4 files changed, 89 insertions(+), 29 deletions(-) diff --git a/Pipfile b/Pipfile index f6f66b28..57c10d1b 100644 --- a/Pipfile +++ b/Pipfile @@ -14,6 +14,7 @@ requests = "==2.20.1" coreapi = "==2.3.3" whitenoise = "==4.1.2" pytz = "==2018.7" +django-rest-swagger = "*" [dev-packages] "flake8" = "*" diff --git a/Pipfile.lock b/Pipfile.lock index 09fda139..077b4a17 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "7eeb23c826a7cad627b63d097d320d7135c3f2d2159800a2d62a13a795fa4428" + "sha256": "907f98a633b030e2075a764acc869211511bd36d4da98034062ccc7477b19f3e" }, "pipfile-spec": 6, "requires": { @@ -18,10 +18,10 @@ "default": { "certifi": { "hashes": [ - "sha256:59b7658e26ca9c7339e00f8f4636cdfe59d34fa37b9b04f6f9e9926b3cece1a5", - "sha256:b26104d6835d1f5e49452a26eb2ff87fe7090b89dfcaee5ea2212697e1e1d7ae" + "sha256:046832c04d4e752f37383b628bc601a7ea7211496b4638f6514d0e5b9acc4939", + "sha256:945e3ba63a0b9f577b1395204e13c3a231f9bc0223888be653286534e5873695" ], - "version": "==2019.3.9" + "version": "==2019.6.16" }, "chardet": { "hashes": [ @@ -77,6 +77,14 @@ "index": "pypi", "version": "==2.0.0" }, + "django-rest-swagger": { + "hashes": [ + "sha256:48f6aded9937e90ae7cbe9e6c932b9744b8af80cc4e010088b3278c700e0685b", + "sha256:b039b0288bab4665cd45dc5d16f94b13911bc4ad0ed55f74ad3b90aa31c87c17" + ], + "index": "pypi", + "version": "==2.2.0" + }, "djangorestframework": { "hashes": [ "sha256:607865b0bb1598b153793892101d881466bd5a991de12bd6229abb18b1c86136", @@ -138,6 +146,12 @@ ], "version": "==1.1.1" }, + "openapi-codec": { + "hashes": [ + "sha256:1bce63289edf53c601ea3683120641407ff6b708803b8954c8a876fe778d2145" + ], + "version": "==1.3.2" + }, "python-decouple": { "hashes": [ "sha256:1317df14b43efee4337a4aa02914bf004f010cd56d6c4bd894e6474ec8c4fe2d" @@ -161,6 +175,23 @@ "index": "pypi", "version": "==2.20.1" }, + "simplejson": { + "hashes": [ + "sha256:067a7177ddfa32e1483ba5169ebea1bc2ea27f224853211ca669325648ca5642", + "sha256:2fc546e6af49fb45b93bbe878dea4c48edc34083729c0abd09981fe55bdf7f91", + "sha256:354fa32b02885e6dae925f1b5bbf842c333c1e11ea5453ddd67309dc31fdb40a", + "sha256:37e685986cf6f8144607f90340cff72d36acf654f3653a6c47b84c5c38d00df7", + "sha256:3af610ee72efbe644e19d5eaad575c73fb83026192114e5f6719f4901097fce2", + "sha256:3b919fc9cf508f13b929a9b274c40786036b31ad28657819b3b9ba44ba651f50", + "sha256:3dd289368bbd064974d9a5961101f080e939cbe051e6689a193c99fb6e9ac89b", + "sha256:6c3258ffff58712818a233b9737fe4be943d306c40cf63d14ddc82ba563f483a", + "sha256:75e3f0b12c28945c08f54350d91e624f8dd580ab74fd4f1bbea54bc6b0165610", + "sha256:b1f329139ba647a9548aa05fb95d046b4a677643070dc2afc05fa2e975d09ca5", + "sha256:ee9625fc8ee164902dfbb0ff932b26df112da9f871c32f0f9c1bcf20c350fe2a", + "sha256:fb2530b53c28f0d4d84990e945c2ebb470edb469d63e389bf02ff409012fe7c5" + ], + "version": "==3.16.0" + }, "uritemplate": { "hashes": [ "sha256:01c69f4fe8ed503b2951bef85d996a9d22434d2431584b5b107b2981ff416fbd", @@ -186,6 +217,14 @@ } }, "develop": { + "appnope": { + "hashes": [ + "sha256:5b26757dc6f79a3b7dc9fab95359328d5747fcb2409d331ea66d0272b90ab2a0", + "sha256:8b995ffe925347a2138d7ac0fe77155e4311a0ea6d6da4f5128fe4b3cbe5ed71" + ], + "markers": "sys_platform == 'darwin'", + "version": "==0.1.0" + }, "autopep8": { "hashes": [ "sha256:4d8eec30cc81bc5617dbf1218201d770dc35629363547f17577c61683ccfb3ee" @@ -202,42 +241,32 @@ }, "coverage": { "hashes": [ - "sha256:0c5fe441b9cfdab64719f24e9684502a59432df7570521563d7b1aff27ac755f", - "sha256:2b412abc4c7d6e019ce7c27cbc229783035eef6d5401695dccba80f481be4eb3", "sha256:3684fabf6b87a369017756b551cef29e505cb155ddb892a7a29277b978da88b9", "sha256:39e088da9b284f1bd17c750ac672103779f7954ce6125fd4382134ac8d152d74", "sha256:3c205bc11cc4fcc57b761c2da73b9b72a59f8d5ca89979afb0c1c6f9e53c7390", - "sha256:42692db854d13c6c5e9541b6ffe0fe921fe16c9c446358d642ccae1462582d3b", "sha256:465ce53a8c0f3a7950dfb836438442f833cf6663d407f37d8c52fe7b6e56d7e8", "sha256:48020e343fc40f72a442c8a1334284620f81295256a6b6ca6d8aa1350c763bbe", - "sha256:4ec30ade438d1711562f3786bea33a9da6107414aed60a5daa974d50a8c2c351", "sha256:5296fc86ab612ec12394565c500b412a43b328b3907c0d14358950d06fd83baf", "sha256:5f61bed2f7d9b6a9ab935150a6b23d7f84b8055524e7be7715b6513f3328138e", - "sha256:6899797ac384b239ce1926f3cb86ffc19996f6fa3a1efbb23cb49e0c12d8c18c", "sha256:68a43a9f9f83693ce0414d17e019daee7ab3f7113a70c79a3dd4c2f704e4d741", "sha256:6b8033d47fe22506856fe450470ccb1d8ba1ffb8463494a15cfc96392a288c09", "sha256:7ad7536066b28863e5835e8cfeaa794b7fe352d99a8cded9f43d1161be8e9fbd", "sha256:7bacb89ccf4bedb30b277e96e4cc68cd1369ca6841bde7b005191b54d3dd1034", "sha256:839dc7c36501254e14331bcb98b27002aa415e4af7ea039d9009409b9d2d5420", - "sha256:8e679d1bde5e2de4a909efb071f14b472a678b788904440779d2c449c0355b27", "sha256:8f9a95b66969cdea53ec992ecea5406c5bd99c9221f539bca1e8406b200ae98c", "sha256:932c03d2d565f75961ba1d3cec41ddde00e162c5b46d03f7423edcb807734eab", - "sha256:93f965415cc51604f571e491f280cff0f5be35895b4eb5e55b47ae90c02a497b", "sha256:988529edadc49039d205e0aa6ce049c5ccda4acb2d6c3c5c550c17e8c02c05ba", "sha256:998d7e73548fe395eeb294495a04d38942edb66d1fa61eb70418871bc621227e", "sha256:9de60893fb447d1e797f6bf08fdf0dbcda0c1e34c1b06c92bd3a363c0ea8c609", "sha256:9e80d45d0c7fcee54e22771db7f1b0b126fb4a6c0a2e5afa72f66827207ff2f2", "sha256:a545a3dfe5082dc8e8c3eb7f8a2cf4f2870902ff1860bd99b6198cfd1f9d1f49", "sha256:a5d8f29e5ec661143621a8f4de51adfb300d7a476224156a39a392254f70687b", - "sha256:a9abc8c480e103dc05d9b332c6cc9fb1586330356fc14f1aa9c0ca5745097d19", "sha256:aca06bfba4759bbdb09bf52ebb15ae20268ee1f6747417837926fae990ebc41d", "sha256:bb23b7a6fd666e551a3094ab896a57809e010059540ad20acbeec03a154224ce", "sha256:bfd1d0ae7e292105f29d7deaa9d8f2916ed8553ab9d5f39ec65bcf5deadff3f9", - "sha256:c22ab9f96cbaff05c6a84e20ec856383d27eae09e511d3e6ac4479489195861d", "sha256:c62ca0a38958f541a73cf86acdab020c2091631c137bd359c4f5bddde7b75fd4", "sha256:c709d8bda72cf4cd348ccec2a4881f2c5848fd72903c185f363d361b2737f773", "sha256:c968a6aa7e0b56ecbd28531ddf439c2ec103610d3e2bf3b75b813304f8cb7723", - "sha256:ca58eba39c68010d7e87a823f22a081b5290e3e3c64714aac3c91481d8b34d22", "sha256:df785d8cb80539d0b55fd47183264b7002077859028dfe3070cf6359bf8b2d9c", "sha256:f406628ca51e0ae90ae76ea8398677a921b36f0bd71aab2099dfed08abd0322f", "sha256:f46087bbd95ebae244a0eda01a618aff11ec7a069b15a3ef8f6b520db523dcf1", @@ -263,19 +292,19 @@ }, "flake8": { "hashes": [ - "sha256:859996073f341f2670741b51ec1e67a01da142831aa1fdc6242dbf88dffbe661", - "sha256:a796a115208f5c03b18f332f7c11729812c8c3ded6c46319c59b53efd3819da8" + "sha256:19241c1cbc971b9962473e4438a2ca19749a7dd002dd1a946eaba171b4114548", + "sha256:8e9dfa3cecb2400b3738a42c54c3043e821682b9c840b0448c0503f781130696" ], "index": "pypi", - "version": "==3.7.7" + "version": "==3.7.8" }, "ipython": { "hashes": [ - "sha256:54c5a8aa1eadd269ac210b96923688ccf01ebb2d0f21c18c3c717909583579a8", - "sha256:e840810029224b56cd0d9e7719dc3b39cf84d577f8ac686547c8ba7a06eeab26" + "sha256:11067ab11d98b1e6c7f0993506f7a5f8a91af420f7e82be6575fcb7a6ca372a0", + "sha256:60bc55c2c1d287161191cc2469e73c116d9b634cff25fe214a43cba7cec94c79" ], "index": "pypi", - "version": "==7.5.0" + "version": "==7.6.1" }, "ipython-genutils": { "hashes": [ @@ -286,10 +315,10 @@ }, "jedi": { "hashes": [ - "sha256:2bb0603e3506f708e792c7f4ad8fc2a7a9d9c2d292a358fbbd58da531695595b", - "sha256:2c6bcd9545c7d6440951b12b44d373479bf18123a401a52025cf98563fbd826c" + "sha256:49ccb782651bb6f7009810d17a3316f8867dde31654c750506970742e18b553d", + "sha256:79d0f6595f3846dffcbe667cc6dc821b96e5baa8add125176c31a3917eb19d58" ], - "version": "==0.13.3" + "version": "==0.14.0" }, "mccabe": { "hashes": [ @@ -300,10 +329,10 @@ }, "parso": { "hashes": [ - "sha256:17cc2d7a945eb42c3569d4564cdf49bde221bc2b552af3eca9c1aad517dcdd33", - "sha256:2e9574cb12e7112a87253e14e2c380ce312060269d04bd018478a3c92ea9a376" + "sha256:5052bb33be034cba784193e74b1cde6ebf29ae8b8c1e4ad94df0c4209bfc4826", + "sha256:db5881df1643bf3e66c097bfd8935cf03eae73f4cb61ae4433c9ea4fb6613446" ], - "version": "==0.4.0" + "version": "==0.5.0" }, "pexpect": { "hashes": [ @@ -351,10 +380,10 @@ }, "pygments": { "hashes": [ - "sha256:5ffada19f6203563680669ee7f53b64dabbeb100eb51b61996085e99c03b284a", - "sha256:e8218dd399a61674745138520d0d4cf2621d7e032439341bc3f647bff125818d" + "sha256:71e430bc85c88a430f000ac1d9b331d2407f681d6f6aec95e8bcfbc3df5b0127", + "sha256:881c4c157e45f30af185c1ffe8d549d48ac9127433f2c380c24b84572ad66297" ], - "version": "==2.3.1" + "version": "==2.4.2" }, "six": { "hashes": [ diff --git a/bothub/settings.py b/bothub/settings.py index 303bd576..3a2e3ef3 100644 --- a/bothub/settings.py +++ b/bothub/settings.py @@ -35,6 +35,7 @@ 'django.contrib.staticfiles', 'rest_framework', 'rest_framework.authtoken', + 'rest_framework_swagger', 'django_filters', 'corsheaders', 'bothub.authentication', @@ -244,3 +245,30 @@ # SECURE PROXY SSL HEADER SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https') + + +# Swagger + +SWAGGER_SETTINGS = { + # 'LOGIN_URL': 'rest_framework:login', + # 'LOGOUT_URL': 'rest_framework:logout', + 'USE_SESSION_AUTH': False, + 'DOC_EXPANSION': 'list', + 'APIS_SORTER': 'alpha', + 'JSON_EDITOR': True, + 'api_version': '0.1', + 'SUPPORTED_SUBMIT_METHODS': [ + 'get', + 'post', + 'put', + 'delete', + ], + # 'SECURITY_DEFINITIONS': { + # "api_key": { + # "type": "apiKey", + # "name": "Authorization", + # "in": "header", + # "description": "JWT authorization" + # }, + # }, +} diff --git a/bothub/urls.py b/bothub/urls.py index b3618f06..e98f6000 100644 --- a/bothub/urls.py +++ b/bothub/urls.py @@ -2,6 +2,7 @@ from django.urls import path, include from django.conf import settings from rest_framework.documentation import include_docs_urls +from rest_framework_swagger.views import get_swagger_view from bothub.api.v1.routers import router as bothub_api_routers from bothub.api.v2 import urls as bothub_api_v2_urls @@ -16,6 +17,7 @@ path('v2/', include(bothub_api_v2_urls)), path('api/v2/', include(bothub_api_v2_urls)), path('docs/', include_docs_urls(title='API Documentation')), + path('docs/swagger/', get_swagger_view(title='API Documentation')), path('admin/', admin.site.urls), path('ping/', ping, name='ping'), path('200/', r200, name='200'), From 0693186677bc7ebaa4701b7d0bf775e135846b9e Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Tue, 9 Jul 2019 18:00:05 -0300 Subject: [PATCH 041/207] Updated lib swagger to drf-yasg (Old Deprecated) --- Pipfile | 3 +- Pipfile.lock | 52 +++++++++++++++++++++++-- bothub/api/v1/serializers/category.py | 1 + bothub/api/v1/serializers/example.py | 6 +++ bothub/api/v1/serializers/repository.py | 4 ++ bothub/api/v1/serializers/request.py | 3 ++ bothub/api/v1/serializers/translate.py | 2 + bothub/api/v1/serializers/update.py | 1 + bothub/api/v1/serializers/user.py | 2 + bothub/api/v1/views.py | 5 +++ bothub/api/v2/evaluate/serializers.py | 6 +++ bothub/api/v2/example/serializers.py | 2 + bothub/api/v2/repository/serializers.py | 7 ++++ bothub/api/v2/request/serializers.py | 1 + bothub/settings.py | 27 ++++--------- bothub/urls.py | 24 ++++++++++-- 16 files changed, 119 insertions(+), 27 deletions(-) diff --git a/Pipfile b/Pipfile index 57c10d1b..742b72c2 100644 --- a/Pipfile +++ b/Pipfile @@ -14,7 +14,8 @@ requests = "==2.20.1" coreapi = "==2.3.3" whitenoise = "==4.1.2" pytz = "==2018.7" -django-rest-swagger = "*" +django-rest-swagger = "==2.1.2" +drf-yasg = "==1.16.0" [dev-packages] "flake8" = "*" diff --git a/Pipfile.lock b/Pipfile.lock index 077b4a17..6c539090 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "907f98a633b030e2075a764acc869211511bd36d4da98034062ccc7477b19f3e" + "sha256": "f1adcf5c367eeab97aafdf2aaf39c70093b46fca6858f3290ec9e9f02a8d9322" }, "pipfile-spec": 6, "requires": { @@ -79,11 +79,11 @@ }, "django-rest-swagger": { "hashes": [ - "sha256:48f6aded9937e90ae7cbe9e6c932b9744b8af80cc4e010088b3278c700e0685b", - "sha256:b039b0288bab4665cd45dc5d16f94b13911bc4ad0ed55f74ad3b90aa31c87c17" + "sha256:3471e6c21a3e97751fa6f7b81b66e916e40fa645cac36be1594c0efed810d247", + "sha256:ff889e2b339a9a57010dba7729d56471e05b77827f6dd36c0bcb983839882598" ], "index": "pypi", - "version": "==2.2.0" + "version": "==2.1.2" }, "djangorestframework": { "hashes": [ @@ -93,6 +93,14 @@ "index": "pypi", "version": "==3.9.0" }, + "drf-yasg": { + "hashes": [ + "sha256:4e282ba668b257bc26b9cddd688e50f7b7f39ad38caa15612b96e8e2bab74904", + "sha256:82b535a22fc13e0a202217df4c6470c40b54d21f742e69798f53c69afccbfdac" + ], + "index": "pypi", + "version": "==1.16.0" + }, "idna": { "hashes": [ "sha256:156a6814fb5ac1fc6850fb002e0852d56c0c8d2531923a51032d1b70760e186e", @@ -100,6 +108,12 @@ ], "version": "==2.7" }, + "inflection": { + "hashes": [ + "sha256:18ea7fb7a7d152853386523def08736aa8c32636b047ade55f7578c4edeb16ca" + ], + "version": "==0.3.1" + }, "itypes": { "hashes": [ "sha256:c6e77bb9fd68a4bfeb9d958fea421802282451a25bac4913ec94db82a899c073" @@ -175,6 +189,29 @@ "index": "pypi", "version": "==2.20.1" }, + "ruamel.yaml": { + "hashes": [ + "sha256:035d1258d1f07c672a55263435a22f3292c50636bf8ed0fa6b90cee0a244e6bd", + "sha256:189437e108ef00104d21ee9aa57b2ae3927f3ab61bef0447a2fd21b82c64e4b2", + "sha256:25bb32cea6ee4bf7da680d80b51ec42081254f30e02d3f58db0653b041ae8185", + "sha256:2852fd6854cd8fb9342ae785d222af3d797e41fa712296f6cf7cd9ae0fee085d", + "sha256:340244ab265943bad541220466e56b0409f5bbcfe3750f417c4c15fabed27a9d", + "sha256:5cdea389d836f6f7386cf32dbe4c29ef82e517559bdf8ba4470ebe9d85ceda4f", + "sha256:6cb78ae9a515936a342adfb114513998a78333441e6599599ab6a7cab90f1999", + "sha256:72a89b03d7e9671340e19ef96ba9cc58b86a079190c0ab89b70ee5458b71748c", + "sha256:86278b7804111b6295069e05266e6faa06a426616ad11597c5c6fed14055b1bb", + "sha256:937908eb1fab3cc997e88960ccce21a44feb31711c2eb00bb2dbdcad645f5e77", + "sha256:95c2f135479957b2d6ca577f8a4bd2d22f78d566250cabf308b75b060100bcd4", + "sha256:9cecfbf214bb6ab93026ea180e429b76e8cc12782f4e531632b0ea0a407be543", + "sha256:a1f78fa84358631025bf393207c0b043b995ae76cb3963ce555be46932792d13", + "sha256:aee248b1583b577cb4dbda1fb24e67baae9af2f25eed849b45d9db077fa62c3b", + "sha256:bb7438aa4f81a0bed286498ec71e68c04f725b153dc52203fa4eed96ee898013", + "sha256:c9685b1788823bc3a34349322cb7268f949a2136d396de2b8044b1cd49cd5370", + "sha256:d3557962da02bbed24157b0de16343f6c264c4b691f6424f3b72dfcecbca592e", + "sha256:e93c86cbaee4c299fff8dbff5df6b22af78846ddd1e9fcb5e238489a4910cf29" + ], + "version": "==0.15.98" + }, "simplejson": { "hashes": [ "sha256:067a7177ddfa32e1483ba5169ebea1bc2ea27f224853211ca669325648ca5642", @@ -192,6 +229,13 @@ ], "version": "==3.16.0" }, + "six": { + "hashes": [ + "sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c", + "sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73" + ], + "version": "==1.12.0" + }, "uritemplate": { "hashes": [ "sha256:01c69f4fe8ed503b2951bef85d996a9d22434d2431584b5b107b2981ff416fbd", diff --git a/bothub/api/v1/serializers/category.py b/bothub/api/v1/serializers/category.py index 2a71af96..07a1437f 100644 --- a/bothub/api/v1/serializers/category.py +++ b/bothub/api/v1/serializers/category.py @@ -11,3 +11,4 @@ class Meta: 'name', 'icon', ] + ref_name = None diff --git a/bothub/api/v1/serializers/example.py b/bothub/api/v1/serializers/example.py index d8e3667c..4213466a 100644 --- a/bothub/api/v1/serializers/example.py +++ b/bothub/api/v1/serializers/example.py @@ -33,6 +33,7 @@ class Meta: 'created_at', 'value', ] + ref_name = None repository_example = serializers.PrimaryKeyRelatedField( queryset=RepositoryExample.objects, @@ -62,6 +63,7 @@ class Meta: 'entity', 'label', ] + ref_name = None repository_example = serializers.PrimaryKeyRelatedField( queryset=RepositoryExample.objects, @@ -107,6 +109,7 @@ class Meta: 'repository_update', 'deleted_in', ] + ref_name = None entities = RepositoryExampleEntitySerializer( many=True, @@ -132,6 +135,7 @@ class Meta: 'intent', 'entities', ] + ref_name = None id = serializers.PrimaryKeyRelatedField( read_only=True, @@ -186,6 +190,7 @@ class Meta: 'value', 'label', ] + ref_name = None label = serializers.SerializerMethodField() @@ -203,6 +208,7 @@ class Meta: 'value', 'entities', ] + ref_name = None repository = serializers.StringRelatedField(read_only=True) entities = serializers.SlugRelatedField( diff --git a/bothub/api/v1/serializers/repository.py b/bothub/api/v1/serializers/repository.py index ac8ad754..7a5c6b92 100644 --- a/bothub/api/v1/serializers/repository.py +++ b/bothub/api/v1/serializers/repository.py @@ -32,6 +32,7 @@ class Meta: 'description', 'is_private', ] + ref_name = None uuid = serializers.ReadOnlyField( style={'show': False}) @@ -86,6 +87,7 @@ class Meta: 'languages_warnings', 'created_at', ] + ref_name = None owner = serializers.PrimaryKeyRelatedField( read_only=True, @@ -172,6 +174,7 @@ class Meta: 'is_admin', 'created_at', ] + ref_name = None user__nickname = serializers.SlugRelatedField( source='user', @@ -194,6 +197,7 @@ class Meta: fields = [ 'role', ] + ref_name = None def validate(self, data): if self.instance.user == self.instance.repository.owner: diff --git a/bothub/api/v1/serializers/request.py b/bothub/api/v1/serializers/request.py index add5e971..dad0c52e 100644 --- a/bothub/api/v1/serializers/request.py +++ b/bothub/api/v1/serializers/request.py @@ -14,6 +14,7 @@ class Meta: 'repository', 'text', ] + ref_name = None repository = serializers.PrimaryKeyRelatedField( queryset=Repository.objects, @@ -41,6 +42,7 @@ class Meta: 'approved_by__nickname', 'created_at', ] + ref_name = None user__nickname = serializers.SlugRelatedField( source='user', @@ -58,6 +60,7 @@ class Meta: fields = [ 'approved_by' ] + ref_name = None approved_by = serializers.PrimaryKeyRelatedField( read_only=True, diff --git a/bothub/api/v1/serializers/translate.py b/bothub/api/v1/serializers/translate.py index 01fa9ce0..673a3d00 100644 --- a/bothub/api/v1/serializers/translate.py +++ b/bothub/api/v1/serializers/translate.py @@ -56,6 +56,7 @@ class Meta: 'entities', 'created_at', ] + ref_name = None original_example = serializers.PrimaryKeyRelatedField( queryset=RepositoryExample.objects, @@ -100,6 +101,7 @@ class Meta: 'has_valid_entities', 'entities', ] + ref_name = None def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) diff --git a/bothub/api/v1/serializers/update.py b/bothub/api/v1/serializers/update.py index 5d3f314b..0cf66704 100644 --- a/bothub/api/v1/serializers/update.py +++ b/bothub/api/v1/serializers/update.py @@ -17,6 +17,7 @@ class Meta: 'trained_at', 'failed_at', ] + ref_name = None by__nickname = serializers.SlugRelatedField( source='by', diff --git a/bothub/api/v1/serializers/user.py b/bothub/api/v1/serializers/user.py index 7032fdca..b45da18b 100644 --- a/bothub/api/v1/serializers/user.py +++ b/bothub/api/v1/serializers/user.py @@ -19,6 +19,7 @@ class Meta: 'nickname', 'password', ] + ref_name = None password = PasswordField( write_only=True, @@ -38,6 +39,7 @@ class Meta: 'name', 'locale', ] + ref_name = None class ChangePasswordSerializer(serializers.Serializer): diff --git a/bothub/api/v1/views.py b/bothub/api/v1/views.py index 2b4be701..0753d646 100644 --- a/bothub/api/v1/views.py +++ b/bothub/api/v1/views.py @@ -710,6 +710,11 @@ class RegisterUserViewSet( class LoginViewSet(GenericViewSet): + + """ + Login Users + """ + queryset = User.objects serializer_class = LoginSerializer diff --git a/bothub/api/v2/evaluate/serializers.py b/bothub/api/v2/evaluate/serializers.py index 35668fc8..27a1deb1 100644 --- a/bothub/api/v2/evaluate/serializers.py +++ b/bothub/api/v2/evaluate/serializers.py @@ -27,6 +27,7 @@ class Meta: 'start', 'end', ] + ref_name = None entity = EntityValueField() @@ -48,6 +49,7 @@ class Meta: 'deleted_in', 'created_at', ] + ref_name = None entities = RepositoryEvaluateEntitySerializer( many=True, @@ -112,6 +114,7 @@ class Meta: 'created_at', 'version', ] + ref_name = None language = serializers.SerializerMethodField() @@ -161,6 +164,7 @@ class Meta: 'intent', 'score', ] + ref_name = None score = RepositoryEvaluateResultScore(read_only=True) @@ -173,6 +177,7 @@ class Meta: 'entity', 'score', ] + ref_name = None score = RepositoryEvaluateResultScore(read_only=True) entity = serializers.SerializerMethodField() @@ -197,6 +202,7 @@ class Meta: 'intent_results', 'entity_results', ] + ref_name = None log = serializers.SerializerMethodField() intents_list = serializers.SerializerMethodField() diff --git a/bothub/api/v2/example/serializers.py b/bothub/api/v2/example/serializers.py index 6996bf05..d96c36e8 100644 --- a/bothub/api/v2/example/serializers.py +++ b/bothub/api/v2/example/serializers.py @@ -18,6 +18,7 @@ class Meta: 'created_at', 'value', ] + ref_name = None repository_example = serializers.PrimaryKeyRelatedField( queryset=RepositoryExample.objects, @@ -53,6 +54,7 @@ class Meta: 'deleted_in', 'translations', ] + ref_name = None entities = RepositoryExampleEntitySerializer( many=True, diff --git a/bothub/api/v2/repository/serializers.py b/bothub/api/v2/repository/serializers.py index cf6fa99b..94232b75 100644 --- a/bothub/api/v2/repository/serializers.py +++ b/bothub/api/v2/repository/serializers.py @@ -18,6 +18,7 @@ class Meta: 'name', 'icon', ] + ref_name = None class RepositoryEntityLabelSerializer(serializers.ModelSerializer): @@ -29,6 +30,7 @@ class Meta: 'entities', 'examples__count', ] + ref_name = None entities = serializers.SerializerMethodField() examples__count = serializers.SerializerMethodField() @@ -75,6 +77,7 @@ class Meta: 'role', 'created_at', ] + ref_name = None user__nickname = serializers.SlugRelatedField( source='user', @@ -132,6 +135,7 @@ class Meta: 'created_at', 'authorization', ] + ref_name = None language = serializers.ChoiceField( LANGUAGE_CHOICES, @@ -263,6 +267,7 @@ class Meta: 'absolute_url', ] read_only = fields + ref_name = None categories = RepositoryCategorySerializer( many=True, @@ -295,6 +300,7 @@ class Meta: 'user', 'created_at', ] + ref_name = None def create(self, validated_data): user = self.context.get('request').user @@ -321,3 +327,4 @@ class Meta: 'role', 'created_at', ] + ref_name = None diff --git a/bothub/api/v2/request/serializers.py b/bothub/api/v2/request/serializers.py index 25467e59..ea16940b 100644 --- a/bothub/api/v2/request/serializers.py +++ b/bothub/api/v2/request/serializers.py @@ -16,6 +16,7 @@ class Meta: 'approved_by__nickname', 'created_at', ] + ref_name = None user__nickname = serializers.SlugRelatedField( source='user', diff --git a/bothub/settings.py b/bothub/settings.py index 3a2e3ef3..dc3a388b 100644 --- a/bothub/settings.py +++ b/bothub/settings.py @@ -35,7 +35,7 @@ 'django.contrib.staticfiles', 'rest_framework', 'rest_framework.authtoken', - 'rest_framework_swagger', + 'drf_yasg', 'django_filters', 'corsheaders', 'bothub.authentication', @@ -250,25 +250,14 @@ # Swagger SWAGGER_SETTINGS = { - # 'LOGIN_URL': 'rest_framework:login', - # 'LOGOUT_URL': 'rest_framework:logout', 'USE_SESSION_AUTH': False, 'DOC_EXPANSION': 'list', 'APIS_SORTER': 'alpha', - 'JSON_EDITOR': True, - 'api_version': '0.1', - 'SUPPORTED_SUBMIT_METHODS': [ - 'get', - 'post', - 'put', - 'delete', - ], - # 'SECURITY_DEFINITIONS': { - # "api_key": { - # "type": "apiKey", - # "name": "Authorization", - # "in": "header", - # "description": "JWT authorization" - # }, - # }, + 'SECURITY_DEFINITIONS': { + "api_key": { + "type": "apiKey", + "name": "Authorization", + "in": "header" + }, + }, } diff --git a/bothub/urls.py b/bothub/urls.py index e98f6000..7baf53e6 100644 --- a/bothub/urls.py +++ b/bothub/urls.py @@ -2,7 +2,10 @@ from django.urls import path, include from django.conf import settings from rest_framework.documentation import include_docs_urls -from rest_framework_swagger.views import get_swagger_view + +from rest_framework import permissions +from drf_yasg.views import get_schema_view +from drf_yasg import openapi from bothub.api.v1.routers import router as bothub_api_routers from bothub.api.v2 import urls as bothub_api_v2_urls @@ -11,20 +14,35 @@ from bothub.common.views import download_bot_data +schema_view = get_schema_view( + openapi.Info( + title="API Documentation", + default_version='v1.0.1', + description="Documentation", + terms_of_service="https://www.google.com/policies/terms/", + contact=openapi.Contact(email="bothub@ilhasoft.com.br"), + license=openapi.License(name="GPL-3.0"), + ), + public=True, + permission_classes=(permissions.AllowAny,), +) + urlpatterns = [ path('', include(bothub_api_routers.urls)), path('api/', include(bothub_api_routers.urls)), path('v2/', include(bothub_api_v2_urls)), path('api/v2/', include(bothub_api_v2_urls)), path('docs/', include_docs_urls(title='API Documentation')), - path('docs/swagger/', get_swagger_view(title='API Documentation')), path('admin/', admin.site.urls), path('ping/', ping, name='ping'), path('200/', r200, name='200'), path( 'downloadbotdata//', download_bot_data, - name='download_bot_data') + name='download_bot_data'), + path(r'^swagger(?P\.json|\.yaml)$', schema_view.without_ui()), + path('swagger/', schema_view.with_ui('swagger')), + path('redoc/', schema_view.with_ui('redoc')) ] if settings.DEBUG: From 44ac01652e322215eb1b3fc06ee4ee439ac768f9 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Wed, 10 Jul 2019 08:51:08 -0300 Subject: [PATCH 042/207] Update path swagger to re_path --- bothub/urls.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bothub/urls.py b/bothub/urls.py index 7baf53e6..fb300ca8 100644 --- a/bothub/urls.py +++ b/bothub/urls.py @@ -1,5 +1,5 @@ from django.contrib import admin -from django.urls import path, include +from django.urls import path, include, re_path from django.conf import settings from rest_framework.documentation import include_docs_urls @@ -40,7 +40,7 @@ 'downloadbotdata//', download_bot_data, name='download_bot_data'), - path(r'^swagger(?P\.json|\.yaml)$', schema_view.without_ui()), + re_path(r'^swagger(?P\.json|\.yaml)$', schema_view.without_ui()), path('swagger/', schema_view.with_ui('swagger')), path('redoc/', schema_view.with_ui('redoc')) ] From a0578a533cb14739e978ab0d125dc8f0dc2846e9 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Wed, 10 Jul 2019 11:23:26 -0300 Subject: [PATCH 043/207] Documentation Evaluate and Repository --- bothub/api/v1/views.py | 16 ++++++ bothub/api/v2/evaluate/views.py | 94 +++++++++++++++++++++++++++++++ bothub/api/v2/repository/views.py | 23 ++++++++ 3 files changed, 133 insertions(+) diff --git a/bothub/api/v1/views.py b/bothub/api/v1/views.py index 0753d646..8eb1b15e 100644 --- a/bothub/api/v1/views.py +++ b/bothub/api/v1/views.py @@ -1,3 +1,6 @@ +from django.utils.decorators import method_decorator +from drf_yasg import openapi +from drf_yasg.utils import swagger_auto_schema from rest_framework.viewsets import GenericViewSet from rest_framework import mixins from rest_framework import permissions @@ -402,6 +405,19 @@ def create(self, request, *args, **kwargs): headers=headers) +@method_decorator( + name='list', + decorator=swagger_auto_schema( + manual_parameters=[ + openapi.Parameter( + 'nickname', + openapi.IN_QUERY, + description="Nickname User to find repositories", + type=openapi.TYPE_STRING + ), + ] + ) +) class SearchRepositoriesViewSet( mixins.ListModelMixin, GenericViewSet): diff --git a/bothub/api/v2/evaluate/views.py b/bothub/api/v2/evaluate/views.py index 6977729b..ff5355ce 100644 --- a/bothub/api/v2/evaluate/views.py +++ b/bothub/api/v2/evaluate/views.py @@ -1,3 +1,6 @@ +from django.utils.decorators import method_decorator +from drf_yasg import openapi +from drf_yasg.utils import swagger_auto_schema from rest_framework.viewsets import GenericViewSet from rest_framework import mixins from rest_framework.permissions import IsAuthenticatedOrReadOnly @@ -23,6 +26,96 @@ from .permissions import RepositoryEvaluateResultPermission +@method_decorator( + name='list', + decorator=swagger_auto_schema( + manual_parameters=[ + openapi.Parameter( + 'repository_uuid', + openapi.IN_QUERY, + description="Repository UUID, calling " + "the parameter through url", + type=openapi.TYPE_STRING, + required=True + ), + ] + ) +) +@method_decorator( + name='create', + decorator=swagger_auto_schema( + manual_parameters=[ + openapi.Parameter( + 'repository_uuid', + openapi.IN_QUERY, + description="Repository UUID, calling " + "the parameter through url", + type=openapi.TYPE_STRING, + required=True + ), + ] + ) +) +@method_decorator( + name='retrieve', + decorator=swagger_auto_schema( + manual_parameters=[ + openapi.Parameter( + 'repository_uuid', + openapi.IN_QUERY, + description="Repository UUID, calling " + "the parameter through url", + type=openapi.TYPE_STRING, + required=True + ), + ] + ) +) +@method_decorator( + name='update', + decorator=swagger_auto_schema( + manual_parameters=[ + openapi.Parameter( + 'repository_uuid', + openapi.IN_QUERY, + description="Repository UUID, calling " + "the parameter through url", + type=openapi.TYPE_STRING, + required=True + ), + ] + ) +) +@method_decorator( + name='partial_update', + decorator=swagger_auto_schema( + manual_parameters=[ + openapi.Parameter( + 'repository_uuid', + openapi.IN_QUERY, + description="Repository UUID, calling " + "the parameter through url", + type=openapi.TYPE_STRING, + required=True + ), + ] + ) +) +@method_decorator( + name='destroy', + decorator=swagger_auto_schema( + manual_parameters=[ + openapi.Parameter( + 'repository_uuid', + openapi.IN_QUERY, + description="Repository UUID, calling " + "the parameter through url", + type=openapi.TYPE_STRING, + required=True + ), + ] + ) +) class EvaluateViewSet( mixins.ListModelMixin, mixins.CreateModelMixin, @@ -42,6 +135,7 @@ class EvaluateViewSet( ] metadata_class = Metadata + def list(self, request, *args, **kwargs): self.filter_class = EvaluatesFilter self.filter_backends = [ diff --git a/bothub/api/v2/repository/views.py b/bothub/api/v2/repository/views.py index 3f7bd691..f7a2e11b 100644 --- a/bothub/api/v2/repository/views.py +++ b/bothub/api/v2/repository/views.py @@ -1,3 +1,6 @@ +from django.utils.decorators import method_decorator +from drf_yasg import openapi +from drf_yasg.utils import swagger_auto_schema from rest_framework.response import Response from rest_framework.viewsets import GenericViewSet from rest_framework import mixins, status @@ -37,6 +40,26 @@ class RepositoryViewSet( metadata_class = Metadata +@method_decorator( + name='list', + decorator=swagger_auto_schema( + manual_parameters=[ + openapi.Parameter( + 'user', + openapi.IN_QUERY, + description="Nickname User to find repositories votes", + type=openapi.TYPE_STRING + ), + openapi.Parameter( + 'repository', + openapi.IN_QUERY, + description="Repository UUID, returns a list of " + "users who voted for this repository", + type=openapi.TYPE_STRING + ), + ] + ) +) class RepositoryVotesViewSet( mixins.CreateModelMixin, mixins.DestroyModelMixin, From a5864b1960ef09eb0bc92643cb0cd647302f153f Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Wed, 10 Jul 2019 14:06:02 -0300 Subject: [PATCH 044/207] Doc Routers deprecated --- bothub/api/v1/views.py | 84 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/bothub/api/v1/views.py b/bothub/api/v1/views.py index 8eb1b15e..d9ac03fe 100644 --- a/bothub/api/v1/views.py +++ b/bothub/api/v1/views.py @@ -486,6 +486,12 @@ def languagesstatus(self, request, **kwargs): 'languages_status': repository.languages_status, }) + @method_decorator( + name='list', + decorator=swagger_auto_schema( + deprecated=True, + ) + ) @action( detail=True, methods=['GET'], @@ -501,6 +507,12 @@ def authorization(self, request, **kwargs): serializer = RepositoryAuthorizationSerializer(user_authorization) return Response(serializer.data) + @method_decorator( + name='list', + decorator=swagger_auto_schema( + deprecated=True, + ) + ) @action( detail=True, methods=['GET'], @@ -553,6 +565,12 @@ def analyze(self, request, **kwargs): message = error.get('message') # pragma: no cover raise APIException(detail=message) # pragma: no cover + @method_decorator( + name='create', + decorator=swagger_auto_schema( + deprecated=True, + ) + ) @action( detail=True, methods=['POST'], @@ -628,6 +646,12 @@ class NewRepositoryExampleViewSet( permission_classes = [permissions.IsAuthenticated] +@method_decorator( + name='retrieve', + decorator=swagger_auto_schema( + deprecated=True, + ) +) class RepositoryExampleViewSet( mixins.RetrieveModelMixin, mixins.DestroyModelMixin, @@ -697,6 +721,12 @@ class RepositoryTranslatedExampleViewSet( ] +@method_decorator( + name='list', + decorator=swagger_auto_schema( + deprecated=True, + ) +) class RepositoryExamplesViewSet( mixins.ListModelMixin, GenericViewSet): @@ -878,6 +908,12 @@ class Categories( pagination_class = None +@method_decorator( + name='list', + decorator=swagger_auto_schema( + deprecated=True, + ) +) class RepositoriesViewSet( mixins.ListModelMixin, GenericViewSet): @@ -921,6 +957,48 @@ class RepositoryAuthorizationViewSet( ] +@method_decorator( + name='update', + decorator=swagger_auto_schema( + manual_parameters=[ + openapi.Parameter( + 'repository__uuid', + openapi.IN_PATH, + description="Repository UUID", + type=openapi.TYPE_STRING, + required=True + ), + openapi.Parameter( + 'user__nickname', + openapi.IN_QUERY, + description="Nickname User", + type=openapi.TYPE_STRING, + required=True + ), + ] + ) +) +@method_decorator( + name='partial_update', + decorator=swagger_auto_schema( + manual_parameters=[ + openapi.Parameter( + 'repository__uuid', + openapi.IN_PATH, + description="Repository UUID", + type=openapi.TYPE_STRING, + required=True + ), + openapi.Parameter( + 'user__nickname', + openapi.IN_QUERY, + description="Nickname User", + type=openapi.TYPE_STRING, + required=True + ), + ] + ) +) class RepositoryAuthorizationRoleViewSet( MultipleFieldLookupMixin, mixins.UpdateModelMixin, @@ -1022,6 +1100,12 @@ def update(self, *args, **kwargs): raise ValidationError(e.message) +@method_decorator( + name='list', + decorator=swagger_auto_schema( + deprecated=True, + ) +) class RepositoryEntitiesViewSet( mixins.ListModelMixin, GenericViewSet): From af00b35ea1e443e7bd653ddcf66d9fe177b1637d Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Wed, 10 Jul 2019 14:19:58 -0300 Subject: [PATCH 045/207] Doc PEP8 --- bothub/api/v2/evaluate/views.py | 1 - bothub/settings.py | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/bothub/api/v2/evaluate/views.py b/bothub/api/v2/evaluate/views.py index ff5355ce..d24613de 100644 --- a/bothub/api/v2/evaluate/views.py +++ b/bothub/api/v2/evaluate/views.py @@ -135,7 +135,6 @@ class EvaluateViewSet( ] metadata_class = Metadata - def list(self, request, *args, **kwargs): self.filter_class = EvaluatesFilter self.filter_backends = [ diff --git a/bothub/settings.py b/bothub/settings.py index dc3a388b..a194d039 100644 --- a/bothub/settings.py +++ b/bothub/settings.py @@ -251,7 +251,7 @@ SWAGGER_SETTINGS = { 'USE_SESSION_AUTH': False, - 'DOC_EXPANSION': 'list', + 'DOC_EXPANSION': 'none', 'APIS_SORTER': 'alpha', 'SECURITY_DEFINITIONS': { "api_key": { From 8bc5ae2a1d04bfc3bf6e00d45c950fc7a0a6fc1d Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Wed, 10 Jul 2019 14:23:43 -0300 Subject: [PATCH 046/207] Doc Repositories Contributions --- bothub/api/v2/repository/views.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/bothub/api/v2/repository/views.py b/bothub/api/v2/repository/views.py index f7a2e11b..9571d012 100644 --- a/bothub/api/v2/repository/views.py +++ b/bothub/api/v2/repository/views.py @@ -127,11 +127,25 @@ class RepositoriesViewSet( ] +@method_decorator( + name='list', + decorator=swagger_auto_schema( + manual_parameters=[ + openapi.Parameter( + 'nickname', + openapi.IN_QUERY, + description="Nickname User", + type=openapi.TYPE_STRING, + required=True + ), + ] + ) +) class RepositoriesContributionsViewSet( mixins.ListModelMixin, GenericViewSet): """ - List Repositories Contributions by user, ?nickname=nickname. + List Repositories Contributions by user. """ serializer_class = RepositoryContributionsSerializer queryset = RepositoryAuthorization.objects.all() From 70ddfdd63262cc0d9d897a7c9f23a9cf188c41f5 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Thu, 11 Jul 2019 08:41:26 -0300 Subject: [PATCH 047/207] Documentation --- bothub/api/v1/views.py | 10 ++++++++++ bothub/settings.py | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/bothub/api/v1/views.py b/bothub/api/v1/views.py index d9ac03fe..b642dd4d 100644 --- a/bothub/api/v1/views.py +++ b/bothub/api/v1/views.py @@ -1063,6 +1063,9 @@ def list(self, request, *args, **kwargs): class RequestAuthorizationViewSet( mixins.CreateModelMixin, GenericViewSet): + """ + Request authorization in the repository + """ serializer_class = NewRequestRepositoryAuthorizationSerializer queryset = RequestRepositoryAuthorization.objects permission_classes = [ @@ -1073,6 +1076,9 @@ class RequestAuthorizationViewSet( class RepositoryAuthorizationRequestsViewSet( mixins.ListModelMixin, GenericViewSet): + """ + List of all authorization requests for a repository + """ queryset = RequestRepositoryAuthorization.objects.exclude( approved_by__isnull=False) serializer_class = RequestRepositoryAuthorizationSerializer @@ -1086,6 +1092,10 @@ class ReviewAuthorizationRequestViewSet( mixins.UpdateModelMixin, mixins.DestroyModelMixin, GenericViewSet): + """ + Authorizes or Removes the user who requested + authorization from a repository + """ queryset = RequestRepositoryAuthorization.objects serializer_class = ReviewAuthorizationRequestSerializer permission_classes = [ diff --git a/bothub/settings.py b/bothub/settings.py index a194d039..dc3a388b 100644 --- a/bothub/settings.py +++ b/bothub/settings.py @@ -251,7 +251,7 @@ SWAGGER_SETTINGS = { 'USE_SESSION_AUTH': False, - 'DOC_EXPANSION': 'none', + 'DOC_EXPANSION': 'list', 'APIS_SORTER': 'alpha', 'SECURITY_DEFINITIONS': { "api_key": { From f62c55a7f93010daf81605d7d5ab9adee60c0f05 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Thu, 11 Jul 2019 09:26:18 -0300 Subject: [PATCH 048/207] Verify sentence and intent --- bothub/api/v1/serializers/example.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/bothub/api/v1/serializers/example.py b/bothub/api/v1/serializers/example.py index d8e3667c..ad3dc288 100644 --- a/bothub/api/v1/serializers/example.py +++ b/bothub/api/v1/serializers/example.py @@ -162,6 +162,20 @@ def __init__(self, *args, **kwargs): def create(self, validated_data): entities_data = validated_data.pop('entities') repository = validated_data.pop('repository') + sentence = validated_data.get('text') + intent = validated_data.get('intent') + + check_exist = self.Meta.model.objects.filter( + text=sentence, + intent=intent, + repository_update__repository=repository + ) + + if check_exist: + raise serializers.ValidationError( + {"detail": "Intention and Sentence already exists"} + ) + try: language = validated_data.pop('language') except KeyError: From 7a0a028e15d8e59c71bef05e75dd346e83b32d6e Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Thu, 11 Jul 2019 11:52:25 -0300 Subject: [PATCH 049/207] Update check validation Intent and Sentence --- bothub/api/v1/serializers/example.py | 15 ++------------- bothub/api/v1/validators.py | 15 +++++++++++++++ 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/bothub/api/v1/serializers/example.py b/bothub/api/v1/serializers/example.py index ad3dc288..4b704a01 100644 --- a/bothub/api/v1/serializers/example.py +++ b/bothub/api/v1/serializers/example.py @@ -16,6 +16,7 @@ from ..validators import CanContributeInRepositoryExampleValidator from ..validators import CanContributeInRepositoryValidator from ..validators import ExampleWithIntentOrEntityValidator +from ..validators import IntentAndSentenceNotExistsValidator from ..validators import EntityNotEqualLabelValidator from .translate import RepositoryTranslatedExampleSerializer @@ -158,23 +159,11 @@ class Meta: def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.validators.append(ExampleWithIntentOrEntityValidator()) + self.validators.append(IntentAndSentenceNotExistsValidator()) def create(self, validated_data): entities_data = validated_data.pop('entities') repository = validated_data.pop('repository') - sentence = validated_data.get('text') - intent = validated_data.get('intent') - - check_exist = self.Meta.model.objects.filter( - text=sentence, - intent=intent, - repository_update__repository=repository - ) - - if check_exist: - raise serializers.ValidationError( - {"detail": "Intention and Sentence already exists"} - ) try: language = validated_data.pop('language') diff --git a/bothub/api/v1/validators.py b/bothub/api/v1/validators.py index 125ed61a..6b96c3b8 100644 --- a/bothub/api/v1/validators.py +++ b/bothub/api/v1/validators.py @@ -3,6 +3,7 @@ from rest_framework.exceptions import ValidationError from bothub.common.models import RepositoryTranslatedExample +from bothub.common.models import RepositoryExample class CanContributeInRepositoryValidator(object): @@ -84,6 +85,20 @@ def __call__(self, attrs): raise ValidationError(_('Define a intent or one entity')) +class IntentAndSentenceNotExistsValidator(object): + def __call__(self, attrs): + repository = attrs.get('repository') + intent = attrs.get('intent') + sentence = attrs.get('text') + + if RepositoryExample.objects.filter( + text=sentence, + intent=intent, + repository_update__repository=repository + ).count(): + raise ValidationError(_('Intention and Sentence already exists')) + + class EntityNotEqualLabelValidator(object): def __call__(self, attrs): entity = attrs.get('entity') From 5f443c540bce20ada8412a46f4f190e9e4c43ccf Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Thu, 11 Jul 2019 14:14:47 -0300 Subject: [PATCH 050/207] Added test if exists registry and check raise --- bothub/api/v1/tests/test_example.py | 30 +++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/bothub/api/v1/tests/test_example.py b/bothub/api/v1/tests/test_example.py index 97d06b62..f5d9161d 100644 --- a/bothub/api/v1/tests/test_example.py +++ b/bothub/api/v1/tests/test_example.py @@ -170,6 +170,36 @@ def test_with_entities(self): len(content_data.get('entities')), 1) + def test_exists_registry(self): + text = 'hi' + intent = 'greet' + self.request( + self.owner_token, + { + 'repository': str(self.repository.uuid), + 'text': text, + 'intent': intent, + 'entities': [], + }) + + response, content_data = self.request( + self.owner_token, + { + 'repository': str(self.repository.uuid), + 'text': text, + 'intent': intent, + 'entities': [], + }) + + self.assertEqual( + content_data.get('non_field_errors')[0], + 'Intention and Sentence already exists' + ) + + self.assertEqual( + response.status_code, + status.HTTP_400_BAD_REQUEST) + def test_with_entities_with_label(self): response, content_data = self.request( self.owner_token, From b353982ad8017b5b5d80ccdf064dcbbdd67581d0 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Thu, 11 Jul 2019 14:34:00 -0300 Subject: [PATCH 051/207] Updated test exists example --- bothub/api/v1/tests/test_example.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/bothub/api/v1/tests/test_example.py b/bothub/api/v1/tests/test_example.py index f5d9161d..9cd9b908 100644 --- a/bothub/api/v1/tests/test_example.py +++ b/bothub/api/v1/tests/test_example.py @@ -170,10 +170,10 @@ def test_with_entities(self): len(content_data.get('entities')), 1) - def test_exists_registry(self): + def test_exists_example(self): text = 'hi' intent = 'greet' - self.request( + response_created, content_data_created = self.request( self.owner_token, { 'repository': str(self.repository.uuid), @@ -182,6 +182,10 @@ def test_exists_registry(self): 'entities': [], }) + self.assertEqual( + response_created.status_code, + status.HTTP_201_CREATED) + response, content_data = self.request( self.owner_token, { From d49fab93b810d3109a419fb4422546f27d00fbe0 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Thu, 11 Jul 2019 16:57:01 -0300 Subject: [PATCH 052/207] [fix] Added Raise after exception connection error nlp --- bothub/common/models.py | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/bothub/common/models.py b/bothub/common/models.py index b19d3dfb..98fb9fd9 100644 --- a/bothub/common/models.py +++ b/bothub/common/models.py @@ -12,6 +12,8 @@ from django.template.loader import render_to_string from django.dispatch import receiver from django.core.exceptions import ValidationError +from rest_framework import status +from rest_framework.exceptions import APIException from bothub.authentication.models import User @@ -203,14 +205,19 @@ def request_nlp_analyze(cls, user_authorization, data): @classmethod def request_nlp_evaluate(cls, user_authorization, data): - r = requests.post( # pragma: no cover - cls.nlp_evaluate_url, - data={ - 'language': data.get('language'), - }, - headers={'Authorization': 'Bearer {}'.format( - user_authorization.uuid)}) - return r # pragma: no cover + try: # pragma: no cover + r = requests.post( # pragma: no cover + cls.nlp_evaluate_url, + data={ + 'language': data.get('language'), + }, + headers={'Authorization': 'Bearer {}'.format( + user_authorization.uuid)}) + return r # pragma: no cover + except requests.exceptions.ConnectionError: # pragma: no cover + raise APIException( # pragma: no cover + {'status_code': status.HTTP_503_SERVICE_UNAVAILABLE}, + code=status.HTTP_503_SERVICE_UNAVAILABLE) @property def available_languages(self): From 3aea9d48f8340a2965ff797c7254f33186666989 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Fri, 12 Jul 2019 11:39:05 -0300 Subject: [PATCH 053/207] [fix] Added Raise after exception connection error nlp --- bothub/common/models.py | 40 +++++++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/bothub/common/models.py b/bothub/common/models.py index 98fb9fd9..b06e7c5f 100644 --- a/bothub/common/models.py +++ b/bothub/common/models.py @@ -184,24 +184,34 @@ class Meta: @classmethod def request_nlp_train(cls, user_authorization): - r = requests.post( # pragma: no cover - cls.nlp_train_url, - data={}, - headers={'Authorization': 'Bearer {}'.format( - user_authorization.uuid)}) - return r # pragma: no cover + try: + r = requests.post( # pragma: no cover + cls.nlp_train_url, + data={}, + headers={'Authorization': 'Bearer {}'.format( + user_authorization.uuid)}) + return r # pragma: no cover + except requests.exceptions.ConnectionError: # pragma: no cover + raise APIException( # pragma: no cover + {'status_code': status.HTTP_503_SERVICE_UNAVAILABLE}, + code=status.HTTP_503_SERVICE_UNAVAILABLE) @classmethod def request_nlp_analyze(cls, user_authorization, data): - r = requests.post( # pragma: no cover - cls.nlp_analyze_url, - data={ - 'text': data.get('text'), - 'language': data.get('language'), - }, - headers={'Authorization': 'Bearer {}'.format( - user_authorization.uuid)}) - return r # pragma: no cover + try: + r = requests.post( # pragma: no cover + cls.nlp_analyze_url, + data={ + 'text': data.get('text'), + 'language': data.get('language'), + }, + headers={'Authorization': 'Bearer {}'.format( + user_authorization.uuid)}) + return r # pragma: no cover + except requests.exceptions.ConnectionError: # pragma: no cover + raise APIException( # pragma: no cover + {'status_code': status.HTTP_503_SERVICE_UNAVAILABLE}, + code=status.HTTP_503_SERVICE_UNAVAILABLE) @classmethod def request_nlp_evaluate(cls, user_authorization, data): From a7469edc4cd93bbb56b8800ae597df73301aa20c Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Tue, 16 Jul 2019 14:31:01 -0300 Subject: [PATCH 054/207] Added filter intent and confidence --- bothub/api/v2/evaluate/serializers.py | 51 ++++++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/bothub/api/v2/evaluate/serializers.py b/bothub/api/v2/evaluate/serializers.py index 35668fc8..821aa65c 100644 --- a/bothub/api/v2/evaluate/serializers.py +++ b/bothub/api/v2/evaluate/serializers.py @@ -214,4 +214,53 @@ def get_entities_list(self, obj): obj.evaluate_result_entity.all(), many=True).data def get_log(self, obj): - return json.loads(obj.log) + intent = self.context.get('request').query_params.get('intent', None) + min_c = self.context.get('request').query_params.get('min', 0) + max_c = self.context.get('request').query_params.get('max', 100) + obj_log = json.loads(obj.log) + b_filter = None + + def check(i, value): + if i['intent'] == value: + return i + + def check_conf(confidence, _min, _max): + min_conf = float(_min) / 100 + max_conf = float(_max) / 100 + + if min_conf <= confidence <= max_conf: + return confidence + + if intent: + b_filter = filter( + None, + list( + map( + lambda x: + check( + x, + intent + ), + obj_log + ) + ) + ) + + if min_c or max_c: + b_filter = filter( + None, + list( + map( + lambda x: + check_conf( + x['intent_prediction']['confidence'], + min_c, + max_c + ), + b_filter if b_filter is not None else obj_log + ) + ) + ) + + return b_filter + return obj_log From 003dc7cd48d13af655b139a433125e1cf3262b34 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Tue, 16 Jul 2019 15:33:10 -0300 Subject: [PATCH 055/207] Added filter intent and confidence --- bothub/api/v2/evaluate/serializers.py | 99 ++++++++++++++------------- 1 file changed, 52 insertions(+), 47 deletions(-) diff --git a/bothub/api/v2/evaluate/serializers.py b/bothub/api/v2/evaluate/serializers.py index 821aa65c..72807ee5 100644 --- a/bothub/api/v2/evaluate/serializers.py +++ b/bothub/api/v2/evaluate/serializers.py @@ -214,53 +214,58 @@ def get_entities_list(self, obj): obj.evaluate_result_entity.all(), many=True).data def get_log(self, obj): - intent = self.context.get('request').query_params.get('intent', None) - min_c = self.context.get('request').query_params.get('min', 0) - max_c = self.context.get('request').query_params.get('max', 100) - obj_log = json.loads(obj.log) - b_filter = None - - def check(i, value): - if i['intent'] == value: - return i - - def check_conf(confidence, _min, _max): - min_conf = float(_min) / 100 - max_conf = float(_max) / 100 - - if min_conf <= confidence <= max_conf: - return confidence - - if intent: - b_filter = filter( - None, - list( - map( - lambda x: - check( - x, - intent - ), - obj_log - ) + intent = self.context.get('request').\ + query_params.get('intent', None) + min_confidence = self.context.get('request').\ + query_params.get('min', None) + max_confidence = self.context.get('request').\ + query_params.get('max', None) + + if intent or min_confidence or max_confidence: + start_filter = True + else: + start_filter = False + + def check(result, value, min_per, max_per, filter_start): + min_confidence = float( + min_per if min_per is not None else 0 + ) / 100 + max_confidence = float( + max_per if max_per is not None else 100 + ) / 100 + + if filter_start: + status = False + if result['intent'] == value: + status = True + + if min_per and max_per: + confidence = result['intent_prediction']['confidence'] + if min_confidence <= confidence <= max_confidence: + status = True + else: + status = False + + if status: + return result + else: + return result + + results = filter( + None, + list( + map( + lambda result: + check( + result, + intent, + min_confidence, + max_confidence, + start_filter + ), + json.loads(obj.log) ) ) + ) - if min_c or max_c: - b_filter = filter( - None, - list( - map( - lambda x: - check_conf( - x['intent_prediction']['confidence'], - min_c, - max_c - ), - b_filter if b_filter is not None else obj_log - ) - ) - ) - - return b_filter - return obj_log + return results From fdaae4d3a023a79c7a83988aeeeb19b74542964b Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Tue, 16 Jul 2019 16:07:39 -0300 Subject: [PATCH 056/207] Added filter intent and confidence --- bothub/api/v2/evaluate/serializers.py | 45 +++++++++++---------------- 1 file changed, 18 insertions(+), 27 deletions(-) diff --git a/bothub/api/v2/evaluate/serializers.py b/bothub/api/v2/evaluate/serializers.py index 72807ee5..82e02f59 100644 --- a/bothub/api/v2/evaluate/serializers.py +++ b/bothub/api/v2/evaluate/serializers.py @@ -221,47 +221,38 @@ def get_log(self, obj): max_confidence = self.context.get('request').\ query_params.get('max', None) - if intent or min_confidence or max_confidence: - start_filter = True - else: - start_filter = False - - def check(result, value, min_per, max_per, filter_start): - min_confidence = float( - min_per if min_per is not None else 0 - ) / 100 - max_confidence = float( - max_per if max_per is not None else 100 - ) / 100 - - if filter_start: - status = False - if result['intent'] == value: - status = True + def check(obj_log, intent, min_per, max_per): + if intent or min_per or max_per: + min_confidence = float( + min_per if min_per is not None else 0 + ) / 100 + max_confidence = float( + max_per if max_per is not None else 100 + ) / 100 + status = True + if not obj_log['intent'] == intent: + status = False if min_per and max_per: - confidence = result['intent_prediction']['confidence'] - if min_confidence <= confidence <= max_confidence: - status = True - else: + confidence = obj_log['intent_prediction']['confidence'] + if not min_confidence <= confidence <= max_confidence: status = False if status: - return result + return obj_log else: - return result + return obj_log results = filter( None, list( map( - lambda result: + lambda obj_log: check( - result, + obj_log, intent, min_confidence, - max_confidence, - start_filter + max_confidence ), json.loads(obj.log) ) From 6b54754c8d034de06ed72ca0d3763f06570d9e73 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Tue, 16 Jul 2019 17:23:27 -0300 Subject: [PATCH 057/207] Added filter intent and confidence --- bothub/api/v2/evaluate/serializers.py | 58 +++++++++++++-------------- 1 file changed, 28 insertions(+), 30 deletions(-) diff --git a/bothub/api/v2/evaluate/serializers.py b/bothub/api/v2/evaluate/serializers.py index 82e02f59..a20c06e8 100644 --- a/bothub/api/v2/evaluate/serializers.py +++ b/bothub/api/v2/evaluate/serializers.py @@ -214,42 +214,40 @@ def get_entities_list(self, obj): obj.evaluate_result_entity.all(), many=True).data def get_log(self, obj): - intent = self.context.get('request').\ - query_params.get('intent', None) - min_confidence = self.context.get('request').\ - query_params.get('min', None) - max_confidence = self.context.get('request').\ - query_params.get('max', None) - - def check(obj_log, intent, min_per, max_per): - if intent or min_per or max_per: - min_confidence = float( - min_per if min_per is not None else 0 - ) / 100 - max_confidence = float( - max_per if max_per is not None else 100 - ) / 100 - status = True - if not obj_log['intent'] == intent: - status = False - - if min_per and max_per: - confidence = obj_log['intent_prediction']['confidence'] - if not min_confidence <= confidence <= max_confidence: - status = False - - if status: - return obj_log - else: - return obj_log + intent = self.context.get('request'). \ + query_params.get('intent') + min_confidence = self.context.get('request'). \ + query_params.get('min') + max_confidence = self.context.get('request'). \ + query_params.get('max') + + def check(log, intent, min_per, max_per): + if not intent and not min_per and not max_per: + return log + + confidence = round(log.get('intent_prediction').get('confidence'), 2) + + has_intent = False + + if log.get('intent') == intent: + has_intent = True + + if min_per and max_per: + min_confidence = round(float(min_per) / 100, 2) + max_confidence = round(float(max_per) / 100, 2) + + has_intent = True if min_confidence <= confidence <= max_confidence else False + + if has_intent: + return log results = filter( None, list( map( - lambda obj_log: + lambda log: check( - obj_log, + log, intent, min_confidence, max_confidence From 084a5da6355666185b5aa7a75884712255a9d9bd Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Wed, 17 Jul 2019 10:03:12 -0300 Subject: [PATCH 058/207] Update filter intent and confidence --- bothub/api/v2/evaluate/serializers.py | 32 ++++++++++++++++++--------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/bothub/api/v2/evaluate/serializers.py b/bothub/api/v2/evaluate/serializers.py index a20c06e8..f72ffa06 100644 --- a/bothub/api/v2/evaluate/serializers.py +++ b/bothub/api/v2/evaluate/serializers.py @@ -1,4 +1,5 @@ import json +import decimal from django.utils.translation import gettext as _ from rest_framework import serializers @@ -221,22 +222,33 @@ def get_log(self, obj): max_confidence = self.context.get('request'). \ query_params.get('max') - def check(log, intent, min_per, max_per): - if not intent and not min_per and not max_per: + def filter_intent(log, intent, min_confidence, max_confidence): + if not intent and not min_confidence and not max_confidence: return log - confidence = round(log.get('intent_prediction').get('confidence'), 2) + decimal.getcontext().rounding = decimal.ROUND_DOWN + + confidence = float( + round( + decimal.Decimal( + log.get('intent_prediction').get('confidence') + ), 2 + ) + ) has_intent = False - if log.get('intent') == intent: - has_intent = True + if min_confidence and max_confidence: + min_confidence = float(str(float(log.get('intent_prediction').get('confidence')) / 100)[:4:]) + max_confidence = float(str(float(max_confidence) / 100)[:4:]) - if min_per and max_per: - min_confidence = round(float(min_per) / 100, 2) - max_confidence = round(float(max_per) / 100, 2) + has_intent = True if \ + min_confidence <= \ + confidence <= \ + max_confidence else False - has_intent = True if min_confidence <= confidence <= max_confidence else False + if log.get('intent') != intent and intent is not None: + has_intent = False if has_intent: return log @@ -246,7 +258,7 @@ def check(log, intent, min_per, max_per): list( map( lambda log: - check( + filter_intent( log, intent, min_confidence, From d247825ad01de25d11a113f57c642602863784dd Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Wed, 17 Jul 2019 10:47:20 -0300 Subject: [PATCH 059/207] PEP8 --- bothub/api/v2/evaluate/serializers.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/bothub/api/v2/evaluate/serializers.py b/bothub/api/v2/evaluate/serializers.py index f72ffa06..1c799140 100644 --- a/bothub/api/v2/evaluate/serializers.py +++ b/bothub/api/v2/evaluate/serializers.py @@ -239,8 +239,17 @@ def filter_intent(log, intent, min_confidence, max_confidence): has_intent = False if min_confidence and max_confidence: - min_confidence = float(str(float(log.get('intent_prediction').get('confidence')) / 100)[:4:]) - max_confidence = float(str(float(max_confidence) / 100)[:4:]) + min_confidence = float( + str( + float( + log.get('intent_prediction').get('confidence') + ) / 100 + )[:4:] + ) + max_confidence = float( + str( + float(max_confidence) / 100)[:4:] + ) has_intent = True if \ min_confidence <= \ From facdea4a53bd22af231da16d8ed7456dc231f834 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Wed, 17 Jul 2019 10:47:31 -0300 Subject: [PATCH 060/207] Added test case evaluate filter --- bothub/api/v2/tests/test_evaluate.py | 233 +++++++++++++++++++++++++++ 1 file changed, 233 insertions(+) diff --git a/bothub/api/v2/tests/test_evaluate.py b/bothub/api/v2/tests/test_evaluate.py index 6d7c7dc9..76971db8 100644 --- a/bothub/api/v2/tests/test_evaluate.py +++ b/bothub/api/v2/tests/test_evaluate.py @@ -520,3 +520,236 @@ def test_okay(self): self.assertEqual( response.status_code, status.HTTP_200_OK) + + +class ListEvaluateResultTestFilterCase(TestCase): + def setUp(self): + self.factory = RequestFactory() + + self.owner, self.owner_token = create_user_and_token('owner') + self.user, self.token = create_user_and_token() + + self.repository = Repository.objects.create( + owner=self.owner, + name='Testing', + slug='test', + language=languages.LANGUAGE_EN + ) + + intent_results = RepositoryEvaluateResultScore.objects.create( + f1_score=0.976, + precision=0.978, + accuracy=0.976, + ) + + entity_results = RepositoryEvaluateResultScore.objects.create( + f1_score=0.977, + precision=0.978, + accuracy=0.978, + ) + + evaluate_log = [ + { + "text": "hey", + "intent": "greet", + "intent_prediction": { + "name": "greet", + "confidence": 0.9263743763408538 + }, + "status": "success" + }, + { + "text": "howdy", + "intent": "greet", + "intent_prediction": { + "name": "greet", + "confidence": 0.8099720606047796 + }, + "status": "success" + }, + { + "text": "hey there", + "intent": "greet", + "intent_prediction": { + "name": "greet", + "confidence": 0.8227075176309955 + }, + "status": "success" + }, + { + "text": "test with nlu", + "intent": "restaurant_search", + "intent_prediction": { + "name": "goodbye", + "confidence": 0.3875259420712092 + }, + "status": "error" + } + ] + + sample_url = 'https://s3.amazonaws.com/bothub-sample' + self.evaluate_result = RepositoryEvaluateResult.objects.create( + repository_update=self.repository.current_update(), + intent_results=intent_results, + entity_results=entity_results, + matrix_chart='{}/confmat.png'.format(sample_url), + confidence_chart='{}/hist.png'.format(sample_url), + log=json.dumps(evaluate_log), + ) + + intent_score_1 = RepositoryEvaluateResultScore.objects.create( + precision=1.0, + recall=1.0, + f1_score=1.0, + support=11, + ) + + intent_score_2 = RepositoryEvaluateResultScore.objects.create( + precision=0.89, + recall=1.0, + f1_score=0.94, + support=8, + ) + + intent_score_3 = RepositoryEvaluateResultScore.objects.create( + precision=1.0, + recall=1.0, + f1_score=1.0, + support=8, + ) + + intent_score_4 = RepositoryEvaluateResultScore.objects.create( + precision=1.0, + recall=0.93, + f1_score=0.97, + support=15, + ) + + RepositoryEvaluateResultIntent.objects.create( + evaluate_result=self.evaluate_result, + intent='affirm', + score=intent_score_1, + ) + + RepositoryEvaluateResultIntent.objects.create( + evaluate_result=self.evaluate_result, + intent='goodbye', + score=intent_score_2, + ) + + RepositoryEvaluateResultIntent.objects.create( + evaluate_result=self.evaluate_result, + intent='greet', + score=intent_score_3, + ) + + RepositoryEvaluateResultIntent.objects.create( + evaluate_result=self.evaluate_result, + intent='restaurant_search', + score=intent_score_4, + ) + + entity_score_1 = RepositoryEvaluateResultScore.objects.create( + precision=1.0, + recall=0.90, + f1_score=0.95, + support=10, + ) + + entity_score_2 = RepositoryEvaluateResultScore.objects.create( + precision=1.0, + recall=0.75, + f1_score=0.86, + support=8, + ) + + RepositoryEvaluateResultEntity.objects.create( + evaluate_result=self.evaluate_result, + entity='cuisine', + score=entity_score_1, + ) + + RepositoryEvaluateResultEntity.objects.create( + evaluate_result=self.evaluate_result, + entity='greet', + score=entity_score_2, + ) + + def request(self, token, params): + authorization_header = { + 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), + } + request = self.factory.get( + '/api/v2/evaluate/results/{}/{}'.format( + self.evaluate_result.id, + params + ), **authorization_header + ) + response = ResultsListViewSet.as_view({'get': 'retrieve'})( + request, + pk=self.evaluate_result.id, + repository_uuid=self.repository.uuid + ) + response.render() + content_data = json.loads(response.content) + return (response, content_data,) + + def test_okay(self): + response, content_data = self.request( + self.owner_token, + '?repository_uuid={}'.format( + self.repository.uuid + ) + ) + self.assertEqual(len(content_data['log']), 4) + self.assertEqual( + response.status_code, + status.HTTP_200_OK) + + def test_okay_intent_filter(self): + response, content_data = self.request( + self.owner_token, + '?repository_uuid={}&intent=greet&min=0&max=100'.format( + self.repository.uuid + ) + ) + self.assertEqual(len(content_data['log']), 3) + self.assertEqual( + response.status_code, + status.HTTP_200_OK) + + def test_okay_without_intent_filter(self): + response, content_data = self.request( + self.owner_token, + '?repository_uuid={}&min=0&max=100'.format( + self.repository.uuid + ) + ) + self.assertEqual(len(content_data['log']), 4) + self.assertEqual( + response.status_code, + status.HTTP_200_OK) + + def test_okay_range_without_intent_filter(self): + response, content_data = self.request( + self.owner_token, + '?repository_uuid={}&min=50&max=80'.format( + self.repository.uuid + ) + ) + self.assertEqual(len(content_data['log']), 2) + self.assertEqual( + response.status_code, + status.HTTP_200_OK) + + def test_okay_range_with_intent_filter(self): + response, content_data = self.request( + self.owner_token, + '?repository_uuid={}&intent=greet&min=50&max=80'.format( + self.repository.uuid + ) + ) + self.assertEqual(len(content_data['log']), 1) + self.assertEqual( + response.status_code, + status.HTTP_200_OK) From 65bd67d73efac2282fe7c088a1b141a3b8feb61f Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Wed, 17 Jul 2019 11:20:21 -0300 Subject: [PATCH 061/207] [fix] Filter and tests evaluate --- bothub/api/v2/evaluate/serializers.py | 25 ++++++------------------- bothub/api/v2/tests/test_evaluate.py | 2 +- 2 files changed, 7 insertions(+), 20 deletions(-) diff --git a/bothub/api/v2/evaluate/serializers.py b/bothub/api/v2/evaluate/serializers.py index 1c799140..974db83c 100644 --- a/bothub/api/v2/evaluate/serializers.py +++ b/bothub/api/v2/evaluate/serializers.py @@ -1,5 +1,5 @@ import json -import decimal +from decimal import Decimal, ROUND_DOWN from django.utils.translation import gettext as _ from rest_framework import serializers @@ -226,30 +226,17 @@ def filter_intent(log, intent, min_confidence, max_confidence): if not intent and not min_confidence and not max_confidence: return log - decimal.getcontext().rounding = decimal.ROUND_DOWN - confidence = float( - round( - decimal.Decimal( - log.get('intent_prediction').get('confidence') - ), 2 - ) + Decimal( + log.get('intent_prediction').get('confidence') + ).quantize(Decimal('0.00'), rounding=ROUND_DOWN) ) has_intent = False if min_confidence and max_confidence: - min_confidence = float( - str( - float( - log.get('intent_prediction').get('confidence') - ) / 100 - )[:4:] - ) - max_confidence = float( - str( - float(max_confidence) / 100)[:4:] - ) + min_confidence = float(min_confidence) / 100 + max_confidence = float(max_confidence) / 100 has_intent = True if \ min_confidence <= \ diff --git a/bothub/api/v2/tests/test_evaluate.py b/bothub/api/v2/tests/test_evaluate.py index 76971db8..41442f4e 100644 --- a/bothub/api/v2/tests/test_evaluate.py +++ b/bothub/api/v2/tests/test_evaluate.py @@ -737,7 +737,7 @@ def test_okay_range_without_intent_filter(self): self.repository.uuid ) ) - self.assertEqual(len(content_data['log']), 2) + self.assertEqual(len(content_data['log']), 1) self.assertEqual( response.status_code, status.HTTP_200_OK) From cd529e81d5f2210da25d0040bd199557f2cc43ad Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Wed, 17 Jul 2019 11:26:59 -0300 Subject: [PATCH 062/207] Update Filter evaluate --- bothub/api/v2/evaluate/serializers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bothub/api/v2/evaluate/serializers.py b/bothub/api/v2/evaluate/serializers.py index 974db83c..ad37cd14 100644 --- a/bothub/api/v2/evaluate/serializers.py +++ b/bothub/api/v2/evaluate/serializers.py @@ -243,7 +243,7 @@ def filter_intent(log, intent, min_confidence, max_confidence): confidence <= \ max_confidence else False - if log.get('intent') != intent and intent is not None: + if intent and log.get('intent') != intent: has_intent = False if has_intent: From 7fdeed9cf3fb7f839c347c4ecab22722580f96fc Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Wed, 17 Jul 2019 14:01:43 -0300 Subject: [PATCH 063/207] Doc Evaluate Results Filter --- bothub/api/v2/evaluate/views.py | 36 +++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/bothub/api/v2/evaluate/views.py b/bothub/api/v2/evaluate/views.py index d24613de..0dd5153d 100644 --- a/bothub/api/v2/evaluate/views.py +++ b/bothub/api/v2/evaluate/views.py @@ -154,6 +154,42 @@ def list(self, request, *args, **kwargs): return super().list(request, *args, **kwargs) +@method_decorator( + name='retrieve', + decorator=swagger_auto_schema( + manual_parameters=[ + openapi.Parameter( + 'intent', + openapi.IN_QUERY, + description="Filter a desired intent", + type=openapi.TYPE_STRING, + required=False + ), + openapi.Parameter( + 'min', + openapi.IN_QUERY, + description="Filter Confidence Percentage", + type=openapi.TYPE_INTEGER, + required=False + ), + openapi.Parameter( + 'max', + openapi.IN_QUERY, + description="Filter Confidence Percentage", + type=openapi.TYPE_INTEGER, + required=False + ), + openapi.Parameter( + 'repository_uuid', + openapi.IN_QUERY, + description="Repository UUID, calling " + "the parameter through url", + type=openapi.TYPE_STRING, + required=True + ), + ] + ) +) class ResultsListViewSet( mixins.ListModelMixin, mixins.RetrieveModelMixin, From 0e4a0450bcf47cd4422b61f967fca1bde77e1f8a Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Wed, 17 Jul 2019 14:48:59 -0300 Subject: [PATCH 064/207] Update Pipenv Swagger --- Pipfile | 4 +- Pipfile.lock | 106 ++++++++++++++++++++++----------------------------- 2 files changed, 47 insertions(+), 63 deletions(-) diff --git a/Pipfile b/Pipfile index 742b72c2..4ef22d6f 100644 --- a/Pipfile +++ b/Pipfile @@ -14,14 +14,14 @@ requests = "==2.20.1" coreapi = "==2.3.3" whitenoise = "==4.1.2" pytz = "==2018.7" -django-rest-swagger = "==2.1.2" -drf-yasg = "==1.16.0" +drf-yasg = "*" [dev-packages] "flake8" = "*" coverage = "*" ipython = "*" autopep8 = "*" +packaging = "*" [requires] python_version = "3.6" diff --git a/Pipfile.lock b/Pipfile.lock index 6c539090..616240ea 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "f1adcf5c367eeab97aafdf2aaf39c70093b46fca6858f3290ec9e9f02a8d9322" + "sha256": "648422adf916fcfeff0b93f66fb660e85da82a5fcf4944bc8d53b7cdf4eb5b82" }, "pipfile-spec": 6, "requires": { @@ -77,14 +77,6 @@ "index": "pypi", "version": "==2.0.0" }, - "django-rest-swagger": { - "hashes": [ - "sha256:3471e6c21a3e97751fa6f7b81b66e916e40fa645cac36be1594c0efed810d247", - "sha256:ff889e2b339a9a57010dba7729d56471e05b77827f6dd36c0bcb983839882598" - ], - "index": "pypi", - "version": "==2.1.2" - }, "djangorestframework": { "hashes": [ "sha256:607865b0bb1598b153793892101d881466bd5a991de12bd6229abb18b1c86136", @@ -95,11 +87,11 @@ }, "drf-yasg": { "hashes": [ - "sha256:4e282ba668b257bc26b9cddd688e50f7b7f39ad38caa15612b96e8e2bab74904", - "sha256:82b535a22fc13e0a202217df4c6470c40b54d21f742e69798f53c69afccbfdac" + "sha256:68fded2ffdf46e03f33e766184b7d8f1e1a5236f94acfd0c4ba932a57b812566", + "sha256:fcef74709ead2b365410be3d12afbfd0a6e49d1efe615a15a929da7e950bb83c" ], "index": "pypi", - "version": "==1.16.0" + "version": "==1.16.1" }, "idna": { "hashes": [ @@ -160,12 +152,6 @@ ], "version": "==1.1.1" }, - "openapi-codec": { - "hashes": [ - "sha256:1bce63289edf53c601ea3683120641407ff6b708803b8954c8a876fe778d2145" - ], - "version": "==1.3.2" - }, "python-decouple": { "hashes": [ "sha256:1317df14b43efee4337a4aa02914bf004f010cd56d6c4bd894e6474ec8c4fe2d" @@ -191,43 +177,26 @@ }, "ruamel.yaml": { "hashes": [ - "sha256:035d1258d1f07c672a55263435a22f3292c50636bf8ed0fa6b90cee0a244e6bd", - "sha256:189437e108ef00104d21ee9aa57b2ae3927f3ab61bef0447a2fd21b82c64e4b2", - "sha256:25bb32cea6ee4bf7da680d80b51ec42081254f30e02d3f58db0653b041ae8185", - "sha256:2852fd6854cd8fb9342ae785d222af3d797e41fa712296f6cf7cd9ae0fee085d", - "sha256:340244ab265943bad541220466e56b0409f5bbcfe3750f417c4c15fabed27a9d", - "sha256:5cdea389d836f6f7386cf32dbe4c29ef82e517559bdf8ba4470ebe9d85ceda4f", - "sha256:6cb78ae9a515936a342adfb114513998a78333441e6599599ab6a7cab90f1999", - "sha256:72a89b03d7e9671340e19ef96ba9cc58b86a079190c0ab89b70ee5458b71748c", - "sha256:86278b7804111b6295069e05266e6faa06a426616ad11597c5c6fed14055b1bb", - "sha256:937908eb1fab3cc997e88960ccce21a44feb31711c2eb00bb2dbdcad645f5e77", - "sha256:95c2f135479957b2d6ca577f8a4bd2d22f78d566250cabf308b75b060100bcd4", - "sha256:9cecfbf214bb6ab93026ea180e429b76e8cc12782f4e531632b0ea0a407be543", - "sha256:a1f78fa84358631025bf393207c0b043b995ae76cb3963ce555be46932792d13", - "sha256:aee248b1583b577cb4dbda1fb24e67baae9af2f25eed849b45d9db077fa62c3b", - "sha256:bb7438aa4f81a0bed286498ec71e68c04f725b153dc52203fa4eed96ee898013", - "sha256:c9685b1788823bc3a34349322cb7268f949a2136d396de2b8044b1cd49cd5370", - "sha256:d3557962da02bbed24157b0de16343f6c264c4b691f6424f3b72dfcecbca592e", - "sha256:e93c86cbaee4c299fff8dbff5df6b22af78846ddd1e9fcb5e238489a4910cf29" - ], - "version": "==0.15.98" - }, - "simplejson": { - "hashes": [ - "sha256:067a7177ddfa32e1483ba5169ebea1bc2ea27f224853211ca669325648ca5642", - "sha256:2fc546e6af49fb45b93bbe878dea4c48edc34083729c0abd09981fe55bdf7f91", - "sha256:354fa32b02885e6dae925f1b5bbf842c333c1e11ea5453ddd67309dc31fdb40a", - "sha256:37e685986cf6f8144607f90340cff72d36acf654f3653a6c47b84c5c38d00df7", - "sha256:3af610ee72efbe644e19d5eaad575c73fb83026192114e5f6719f4901097fce2", - "sha256:3b919fc9cf508f13b929a9b274c40786036b31ad28657819b3b9ba44ba651f50", - "sha256:3dd289368bbd064974d9a5961101f080e939cbe051e6689a193c99fb6e9ac89b", - "sha256:6c3258ffff58712818a233b9737fe4be943d306c40cf63d14ddc82ba563f483a", - "sha256:75e3f0b12c28945c08f54350d91e624f8dd580ab74fd4f1bbea54bc6b0165610", - "sha256:b1f329139ba647a9548aa05fb95d046b4a677643070dc2afc05fa2e975d09ca5", - "sha256:ee9625fc8ee164902dfbb0ff932b26df112da9f871c32f0f9c1bcf20c350fe2a", - "sha256:fb2530b53c28f0d4d84990e945c2ebb470edb469d63e389bf02ff409012fe7c5" - ], - "version": "==3.16.0" + "sha256:08aaaa74ff66565024ecabf9ba2db212712382a21c0458f9a91c623a1fa83b34", + "sha256:23f2efb872d2ebe3d5428b4f1a8f30cbf59f56e780c4981c155411ee65572673", + "sha256:38718e69270141c403b5fc539f774ed394568f8a5195b507991f5b690356facb", + "sha256:44da2be1153e173f90ad8775d4ac4237a3c06cfbb9660c1c1980271621833faa", + "sha256:4b1674a936cdae9735578d4fd64bcbc6cfbb77a1a8f7037a50c6e3874ba4c9d8", + "sha256:51d49c870aca850e652e2cd1c9bea9b52b77d13ad52b0556de496c1d264ea65f", + "sha256:63dc8c6147a4cf77efadf2ae0f34e89e03de79289298bb941b7ae333d5d4020b", + "sha256:6672798c6b52a976a7b24e20665055852388c83198d88029d3c76e2197ac221a", + "sha256:6b6025f9b6a557e15e9fdfda4d9af0b57cd8d59ff98e23a0097ab2d7c0540f07", + "sha256:7b750252e3d1ec5b53d03be508796c04a907060900c7d207280b7456650ebbfc", + "sha256:847177699994f9c31adf78d1ef1ff8f069ef0241e744a3ee8b30fbdaa914cc1e", + "sha256:8e42f3067a59e819935a2926e247170ed93c8f0b2ab64526f888e026854db2e4", + "sha256:922d9e483c05d9000256640026f277fcc0c2e1e9271d05acada8e6cfb4c8b721", + "sha256:92a8ca79f9173cca29ca9663b49d9c936aefc4c8a76f39318b0218c8f3626438", + "sha256:ab8eeca4de4decf0d0a42cb6949d354da9fc70a2d9201f0dd55186c599b2e3a5", + "sha256:bd4b60b649f4a81086f70cd56eff4722018ef36a28094c396f1a53bf450bd579", + "sha256:fc6471ef15b69e454cca82433ac5f84929d9f3e2d72b9e54b06850b6b7133cc0", + "sha256:ffc89770339191acbe5a15041950b5ad9daec7d659619b0ed9dad8c9c80c26f3" + ], + "version": "==0.15.100" }, "six": { "hashes": [ @@ -359,10 +328,10 @@ }, "jedi": { "hashes": [ - "sha256:49ccb782651bb6f7009810d17a3316f8867dde31654c750506970742e18b553d", - "sha256:79d0f6595f3846dffcbe667cc6dc821b96e5baa8add125176c31a3917eb19d58" + "sha256:53c850f1a7d3cfcd306cc513e2450a54bdf5cacd7604b74e42dd1f0758eaaf36", + "sha256:e07457174ef7cb2342ff94fa56484fe41cec7ef69b0059f01d3f812379cb6f7c" ], - "version": "==0.14.0" + "version": "==0.14.1" }, "mccabe": { "hashes": [ @@ -371,12 +340,20 @@ ], "version": "==0.6.1" }, + "packaging": { + "hashes": [ + "sha256:0c98a5d0be38ed775798ece1b9727178c4469d9c3b4ada66e8e6b7849f8732af", + "sha256:9e1cbf8c12b1f1ce0bb5344b8d7ecf66a6f8a6e91bcb0c84593ed6d3ab5c4ab3" + ], + "index": "pypi", + "version": "==19.0" + }, "parso": { "hashes": [ - "sha256:5052bb33be034cba784193e74b1cde6ebf29ae8b8c1e4ad94df0c4209bfc4826", - "sha256:db5881df1643bf3e66c097bfd8935cf03eae73f4cb61ae4433c9ea4fb6613446" + "sha256:63854233e1fadb5da97f2744b6b24346d2750b85965e7e399bec1620232797dc", + "sha256:666b0ee4a7a1220f65d367617f2cd3ffddff3e205f3f16a0284df30e774c2a9c" ], - "version": "==0.5.0" + "version": "==0.5.1" }, "pexpect": { "hashes": [ @@ -429,6 +406,13 @@ ], "version": "==2.4.2" }, + "pyparsing": { + "hashes": [ + "sha256:1873c03321fc118f4e9746baf201ff990ceb915f433f23b395f5580d1840cb2a", + "sha256:9b6323ef4ab914af344ba97510e966d64ba91055d6b9afa6b30799340e89cc03" + ], + "version": "==2.4.0" + }, "six": { "hashes": [ "sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c", From 6114c28b2f26f833177974bcc2aa116ba4844a21 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Thu, 18 Jul 2019 11:28:25 -0300 Subject: [PATCH 065/207] Change " to ' --- bothub/api/v1/views.py | 10 ++++----- bothub/api/v2/evaluate/views.py | 34 +++++++++++++++---------------- bothub/api/v2/repository/views.py | 6 +++--- bothub/settings.py | 8 ++++---- bothub/urls.py | 11 +++++----- 5 files changed, 34 insertions(+), 35 deletions(-) diff --git a/bothub/api/v1/views.py b/bothub/api/v1/views.py index b642dd4d..84311ce4 100644 --- a/bothub/api/v1/views.py +++ b/bothub/api/v1/views.py @@ -412,7 +412,7 @@ def create(self, request, *args, **kwargs): openapi.Parameter( 'nickname', openapi.IN_QUERY, - description="Nickname User to find repositories", + description='Nickname User to find repositories', type=openapi.TYPE_STRING ), ] @@ -964,14 +964,14 @@ class RepositoryAuthorizationViewSet( openapi.Parameter( 'repository__uuid', openapi.IN_PATH, - description="Repository UUID", + description='Repository UUID', type=openapi.TYPE_STRING, required=True ), openapi.Parameter( 'user__nickname', openapi.IN_QUERY, - description="Nickname User", + description='Nickname User', type=openapi.TYPE_STRING, required=True ), @@ -985,14 +985,14 @@ class RepositoryAuthorizationViewSet( openapi.Parameter( 'repository__uuid', openapi.IN_PATH, - description="Repository UUID", + description='Repository UUID', type=openapi.TYPE_STRING, required=True ), openapi.Parameter( 'user__nickname', openapi.IN_QUERY, - description="Nickname User", + description='Nickname User', type=openapi.TYPE_STRING, required=True ), diff --git a/bothub/api/v2/evaluate/views.py b/bothub/api/v2/evaluate/views.py index 0dd5153d..87e13e6d 100644 --- a/bothub/api/v2/evaluate/views.py +++ b/bothub/api/v2/evaluate/views.py @@ -33,8 +33,8 @@ openapi.Parameter( 'repository_uuid', openapi.IN_QUERY, - description="Repository UUID, calling " - "the parameter through url", + description='Repository UUID, calling ' + 'the parameter through url', type=openapi.TYPE_STRING, required=True ), @@ -48,8 +48,8 @@ openapi.Parameter( 'repository_uuid', openapi.IN_QUERY, - description="Repository UUID, calling " - "the parameter through url", + description='Repository UUID, calling ' + 'the parameter through url', type=openapi.TYPE_STRING, required=True ), @@ -63,8 +63,8 @@ openapi.Parameter( 'repository_uuid', openapi.IN_QUERY, - description="Repository UUID, calling " - "the parameter through url", + description='Repository UUID, calling ' + 'the parameter through url', type=openapi.TYPE_STRING, required=True ), @@ -78,8 +78,8 @@ openapi.Parameter( 'repository_uuid', openapi.IN_QUERY, - description="Repository UUID, calling " - "the parameter through url", + description='Repository UUID, calling ' + 'the parameter through url', type=openapi.TYPE_STRING, required=True ), @@ -93,8 +93,8 @@ openapi.Parameter( 'repository_uuid', openapi.IN_QUERY, - description="Repository UUID, calling " - "the parameter through url", + description='Repository UUID, calling ' + 'the parameter through url', type=openapi.TYPE_STRING, required=True ), @@ -108,8 +108,8 @@ openapi.Parameter( 'repository_uuid', openapi.IN_QUERY, - description="Repository UUID, calling " - "the parameter through url", + description='Repository UUID, calling ' + 'the parameter through url', type=openapi.TYPE_STRING, required=True ), @@ -161,29 +161,29 @@ def list(self, request, *args, **kwargs): openapi.Parameter( 'intent', openapi.IN_QUERY, - description="Filter a desired intent", + description='Filter a desired intent', type=openapi.TYPE_STRING, required=False ), openapi.Parameter( 'min', openapi.IN_QUERY, - description="Filter Confidence Percentage", + description='Filter Confidence Percentage', type=openapi.TYPE_INTEGER, required=False ), openapi.Parameter( 'max', openapi.IN_QUERY, - description="Filter Confidence Percentage", + description='Filter Confidence Percentage', type=openapi.TYPE_INTEGER, required=False ), openapi.Parameter( 'repository_uuid', openapi.IN_QUERY, - description="Repository UUID, calling " - "the parameter through url", + description='Repository UUID, calling ' + 'the parameter through url', type=openapi.TYPE_STRING, required=True ), diff --git a/bothub/api/v2/repository/views.py b/bothub/api/v2/repository/views.py index 9571d012..1239a0e6 100644 --- a/bothub/api/v2/repository/views.py +++ b/bothub/api/v2/repository/views.py @@ -47,14 +47,14 @@ class RepositoryViewSet( openapi.Parameter( 'user', openapi.IN_QUERY, - description="Nickname User to find repositories votes", + description='Nickname User to find repositories votes', type=openapi.TYPE_STRING ), openapi.Parameter( 'repository', openapi.IN_QUERY, - description="Repository UUID, returns a list of " - "users who voted for this repository", + description='Repository UUID, returns a list of ' + 'users who voted for this repository', type=openapi.TYPE_STRING ), ] diff --git a/bothub/settings.py b/bothub/settings.py index dc3a388b..9d006705 100644 --- a/bothub/settings.py +++ b/bothub/settings.py @@ -254,10 +254,10 @@ 'DOC_EXPANSION': 'list', 'APIS_SORTER': 'alpha', 'SECURITY_DEFINITIONS': { - "api_key": { - "type": "apiKey", - "name": "Authorization", - "in": "header" + 'api_key': { + 'type': 'apiKey', + 'name': 'Authorization', + 'in': 'header' }, }, } diff --git a/bothub/urls.py b/bothub/urls.py index fb300ca8..f31b8247 100644 --- a/bothub/urls.py +++ b/bothub/urls.py @@ -16,11 +16,11 @@ schema_view = get_schema_view( openapi.Info( - title="API Documentation", + title='API Documentation', default_version='v1.0.1', - description="Documentation", - terms_of_service="https://www.google.com/policies/terms/", - contact=openapi.Contact(email="bothub@ilhasoft.com.br"), + description='Documentation', + terms_of_service='https://www.google.com/policies/terms/', + contact=openapi.Contact(email='bothub@ilhasoft.com.br'), license=openapi.License(name="GPL-3.0"), ), public=True, @@ -41,8 +41,7 @@ download_bot_data, name='download_bot_data'), re_path(r'^swagger(?P\.json|\.yaml)$', schema_view.without_ui()), - path('swagger/', schema_view.with_ui('swagger')), - path('redoc/', schema_view.with_ui('redoc')) + path('swagger/', schema_view.with_ui('swagger')) ] if settings.DEBUG: From b2c1b8f245a4087c8592bb674394a28d0fdfaad2 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Thu, 18 Jul 2019 11:44:54 -0300 Subject: [PATCH 066/207] Change " to ' --- bothub/api/v2/repository/views.py | 2 +- bothub/urls.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bothub/api/v2/repository/views.py b/bothub/api/v2/repository/views.py index 1239a0e6..c2d90f91 100644 --- a/bothub/api/v2/repository/views.py +++ b/bothub/api/v2/repository/views.py @@ -134,7 +134,7 @@ class RepositoriesViewSet( openapi.Parameter( 'nickname', openapi.IN_QUERY, - description="Nickname User", + description='Nickname User', type=openapi.TYPE_STRING, required=True ), diff --git a/bothub/urls.py b/bothub/urls.py index f31b8247..9c8085f2 100644 --- a/bothub/urls.py +++ b/bothub/urls.py @@ -21,7 +21,7 @@ description='Documentation', terms_of_service='https://www.google.com/policies/terms/', contact=openapi.Contact(email='bothub@ilhasoft.com.br'), - license=openapi.License(name="GPL-3.0"), + license=openapi.License(name='GPL-3.0'), ), public=True, permission_classes=(permissions.AllowAny,), From 831e3405466cdb560b13fa409948f21f10fbb38f Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Thu, 18 Jul 2019 11:55:12 -0300 Subject: [PATCH 067/207] Update --- bothub/urls.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bothub/urls.py b/bothub/urls.py index 9c8085f2..bf8d6459 100644 --- a/bothub/urls.py +++ b/bothub/urls.py @@ -24,7 +24,7 @@ license=openapi.License(name='GPL-3.0'), ), public=True, - permission_classes=(permissions.AllowAny,), + permission_classes=[permissions.AllowAny], ) urlpatterns = [ From b1db1f4d7b8aad67a94ed1e23bfd68c6760e773f Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Thu, 18 Jul 2019 16:17:44 -0300 Subject: [PATCH 068/207] Migration Login v1 to v2 and refact --- bothub/api/v1/views.py | 7 +++++ bothub/api/v2/account/__init__.py | 0 bothub/api/v2/account/serializers.py | 23 ++++++++++++++++ bothub/api/v2/account/views.py | 41 ++++++++++++++++++++++++++++ bothub/api/v2/metadata.py | 12 +++++++- bothub/api/v2/routers.py | 2 ++ 6 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 bothub/api/v2/account/__init__.py create mode 100644 bothub/api/v2/account/serializers.py create mode 100644 bothub/api/v2/account/views.py diff --git a/bothub/api/v1/views.py b/bothub/api/v1/views.py index 84311ce4..d72315b8 100644 --- a/bothub/api/v1/views.py +++ b/bothub/api/v1/views.py @@ -755,6 +755,13 @@ class RegisterUserViewSet( serializer_class = RegisterUserSerializer +@method_decorator( + name='create', + decorator=swagger_auto_schema( + responses={201: '{"token":"TOKEN"}'}, + deprecated=True + ), +) class LoginViewSet(GenericViewSet): """ diff --git a/bothub/api/v2/account/__init__.py b/bothub/api/v2/account/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/bothub/api/v2/account/serializers.py b/bothub/api/v2/account/serializers.py new file mode 100644 index 00000000..e5710616 --- /dev/null +++ b/bothub/api/v2/account/serializers.py @@ -0,0 +1,23 @@ +from rest_framework.authtoken.serializers import AuthTokenSerializer +from rest_framework import serializers + +from bothub.authentication.models import User +from ..fields import PasswordField +from django.utils.translation import gettext as _ + + +class LoginSerializer(AuthTokenSerializer, serializers.ModelSerializer): + username = serializers.EmailField( + label=_('Email'), + ) + password = PasswordField( + label=_('Password'), + ) + + class Meta: + model = User + fields = [ + 'username', + 'password', + ] + ref_name = None diff --git a/bothub/api/v2/account/views.py b/bothub/api/v2/account/views.py new file mode 100644 index 00000000..a68a288c --- /dev/null +++ b/bothub/api/v2/account/views.py @@ -0,0 +1,41 @@ +from django.utils.decorators import method_decorator +from rest_framework.viewsets import GenericViewSet +from rest_framework.response import Response +from rest_framework.authtoken.models import Token +from rest_framework import status, mixins +from drf_yasg.utils import swagger_auto_schema +from bothub.api.v2.metadata import Metadata +from bothub.authentication.models import User + +from .serializers import LoginSerializer + + +@method_decorator( + name='create', + decorator=swagger_auto_schema( + responses={201: '{"token":"TOKEN"}'} + ) +) +class LoginViewSet(mixins.CreateModelMixin, GenericViewSet): + + """ + Login Users + """ + + queryset = User.objects + serializer_class = LoginSerializer + lookup_field = ('username', 'password') + metadata_class = Metadata + + def create(self, request, *args, **kwargs): + serializer = self.serializer_class( + data=request.data, + context={'request': request}) + serializer.is_valid(raise_exception=True) + user = serializer.validated_data['user'] + token, created = Token.objects.get_or_create(user=user) + return Response( + { + 'token': token.key, + }, + status.HTTP_201_CREATED if created else status.HTTP_200_OK) diff --git a/bothub/api/v2/metadata.py b/bothub/api/v2/metadata.py index 0677bc7e..6a0f707c 100644 --- a/bothub/api/v2/metadata.py +++ b/bothub/api/v2/metadata.py @@ -5,6 +5,11 @@ from rest_framework import serializers from rest_framework.utils.field_mapping import ClassLookupDict +from bothub.api.v2.fields import PasswordField +from bothub.api.v2.fields import ModelMultipleChoiceField +from bothub.api.v2.fields import TextField +from bothub.api.v2.fields import EntityText + class Metadata(BaseMetadata): label_lookup = ClassLookupDict({ @@ -30,6 +35,11 @@ class Metadata(BaseMetadata): serializers.DictField: 'nested object', serializers.Serializer: 'nested object', serializers.ManyRelatedField: 'multiple choice', + serializers.HiddenField: 'hidden', + PasswordField: 'password', + ModelMultipleChoiceField: 'multiple choice', + TextField: 'text', + EntityText: 'entity text', }) def determine_metadata(self, request, view): @@ -52,7 +62,7 @@ def determine_metadata(self, request, view): def determine_actions(self, request, view): actions = {} - for method in ['PUT', 'POST']: + for method in {'PUT', 'POST'} & set(view.allowed_methods): serializer = view.get_serializer() actions[method] = self.get_serializer_info(serializer) view.request = request diff --git a/bothub/api/v2/routers.py b/bothub/api/v2/routers.py index 680ee2c7..b8cac740 100644 --- a/bothub/api/v2/routers.py +++ b/bothub/api/v2/routers.py @@ -7,6 +7,7 @@ from .examples.views import ExamplesViewSet from .evaluate.views import EvaluateViewSet from .evaluate.views import ResultsListViewSet +from .account.views import LoginViewSet router = routers.SimpleRouter() @@ -17,3 +18,4 @@ router.register('examples', ExamplesViewSet) router.register('evaluate/results', ResultsListViewSet) router.register('evaluate', EvaluateViewSet) +router.register('account/login', LoginViewSet) From aebc23ec519fc60ce0d6df845af7b2891d0858ec Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Thu, 18 Jul 2019 16:26:50 -0300 Subject: [PATCH 069/207] Migration Register v1 to v2 and refact --- bothub/api/v1/views.py | 6 ++++++ bothub/api/v2/account/serializers.py | 26 +++++++++++++++++++++++++- bothub/api/v2/account/views.py | 13 +++++++++++++ bothub/api/v2/routers.py | 3 ++- 4 files changed, 46 insertions(+), 2 deletions(-) diff --git a/bothub/api/v1/views.py b/bothub/api/v1/views.py index d72315b8..db7b7d74 100644 --- a/bothub/api/v1/views.py +++ b/bothub/api/v1/views.py @@ -745,6 +745,12 @@ class RepositoryExamplesViewSet( ] +@method_decorator( + name='create', + decorator=swagger_auto_schema( + deprecated=True + ), +) class RegisterUserViewSet( mixins.CreateModelMixin, GenericViewSet): diff --git a/bothub/api/v2/account/serializers.py b/bothub/api/v2/account/serializers.py index e5710616..75f54483 100644 --- a/bothub/api/v2/account/serializers.py +++ b/bothub/api/v2/account/serializers.py @@ -1,9 +1,11 @@ +from django.utils.translation import gettext as _ +from django.contrib.auth.password_validation import validate_password +from django.contrib.auth.hashers import make_password from rest_framework.authtoken.serializers import AuthTokenSerializer from rest_framework import serializers from bothub.authentication.models import User from ..fields import PasswordField -from django.utils.translation import gettext as _ class LoginSerializer(AuthTokenSerializer, serializers.ModelSerializer): @@ -21,3 +23,25 @@ class Meta: 'password', ] ref_name = None + + +class RegisterUserSerializer(serializers.ModelSerializer): + class Meta: + model = User + fields = [ + 'email', + 'name', + 'nickname', + 'password', + ] + ref_name = None + + password = PasswordField( + write_only=True, + validators=[ + validate_password, + ]) + + @staticmethod + def validate_password(value): + return make_password(value) diff --git a/bothub/api/v2/account/views.py b/bothub/api/v2/account/views.py index a68a288c..403d423d 100644 --- a/bothub/api/v2/account/views.py +++ b/bothub/api/v2/account/views.py @@ -8,6 +8,7 @@ from bothub.authentication.models import User from .serializers import LoginSerializer +from .serializers import RegisterUserSerializer @method_decorator( @@ -39,3 +40,15 @@ def create(self, request, *args, **kwargs): 'token': token.key, }, status.HTTP_201_CREATED if created else status.HTTP_200_OK) + + +class RegisterUserViewSet( + mixins.CreateModelMixin, + GenericViewSet): + """ + Register new user + """ + queryset = User.objects + serializer_class = RegisterUserSerializer + lookup_field = ('email', 'name', 'nickname', 'password') + metadata_class = Metadata diff --git a/bothub/api/v2/routers.py b/bothub/api/v2/routers.py index b8cac740..37d5dc5a 100644 --- a/bothub/api/v2/routers.py +++ b/bothub/api/v2/routers.py @@ -8,7 +8,7 @@ from .evaluate.views import EvaluateViewSet from .evaluate.views import ResultsListViewSet from .account.views import LoginViewSet - +from .account.views import RegisterUserViewSet router = routers.SimpleRouter() router.register('repository', RepositoryViewSet) @@ -19,3 +19,4 @@ router.register('evaluate/results', ResultsListViewSet) router.register('evaluate', EvaluateViewSet) router.register('account/login', LoginViewSet) +router.register('account/register', RegisterUserViewSet) From 4d144604636f729a3c10c1c13bd08dd59f1812ed Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Thu, 18 Jul 2019 17:41:18 -0300 Subject: [PATCH 070/207] Custom Routers v2 --- bothub/api/v2/evaluate/views.py | 2 - bothub/api/v2/repository/views.py | 2 +- bothub/api/v2/routers.py | 72 ++++++++++++++++++++++++++++++- 3 files changed, 72 insertions(+), 4 deletions(-) diff --git a/bothub/api/v2/evaluate/views.py b/bothub/api/v2/evaluate/views.py index 87e13e6d..6bb6b471 100644 --- a/bothub/api/v2/evaluate/views.py +++ b/bothub/api/v2/evaluate/views.py @@ -126,7 +126,6 @@ class EvaluateViewSet( """ Manager evaluate (tests). """ - lookup_fields = ('pk', 'repository_uuid') queryset = RepositoryEvaluate.objects serializer_class = RepositoryEvaluateSerializer permission_classes = [ @@ -196,7 +195,6 @@ class ResultsListViewSet( GenericViewSet): queryset = RepositoryEvaluateResult.objects - lookup_fields = ['repository_uuid'] serializer_class = RepositoryEvaluateResultVersionsSerializer permission_classes = [ IsAuthenticated, diff --git a/bothub/api/v2/repository/views.py b/bothub/api/v2/repository/views.py index c2d90f91..f4379cdc 100644 --- a/bothub/api/v2/repository/views.py +++ b/bothub/api/v2/repository/views.py @@ -70,7 +70,7 @@ class RepositoryVotesViewSet( """ queryset = RepositoryVote.objects.all() lookup_field = 'repository' - lookup_fields = ['user', 'repository'] + lookup_fields = ['repository'] serializer_class = RepositoryVotesSerializer permission_classes = [ IsAuthenticatedOrReadOnly diff --git a/bothub/api/v2/routers.py b/bothub/api/v2/routers.py index 37d5dc5a..f49d1aa0 100644 --- a/bothub/api/v2/routers.py +++ b/bothub/api/v2/routers.py @@ -10,7 +10,77 @@ from .account.views import LoginViewSet from .account.views import RegisterUserViewSet -router = routers.SimpleRouter() + +class Router(routers.SimpleRouter): + routes = [ + # Dynamically generated list routes. + # Generated using @action decorator + # on methods of the viewset. + routers.DynamicRoute( + url=r'^{prefix}/{url_path}{trailing_slash}$', + name='{basename}-{url_name}', + detail=True, + initkwargs={}, + ), + # Dynamically generated detail routes. + # Generated using @action decorator on methods of the viewset. + routers.DynamicRoute( + url=r'^{prefix}/{lookup}/{url_path}{trailing_slash}$', + name='{basename}-{url_name}', + detail=True, + initkwargs={}, + ), + ] + + def get_routes(self, viewset): + ret = super().get_routes(viewset) + lookup_field = getattr(viewset, 'lookup_field', None) + + if lookup_field: + # List route. + ret.append(routers.Route( + url=r'^{prefix}{trailing_slash}$', + mapping={ + 'get': 'list', + 'post': 'create' + }, + name='{basename}-list', + detail=False, + initkwargs={'suffix': 'List'}, + )) + + detail_url_regex = r'^{prefix}/{lookup}{trailing_slash}$' + if not lookup_field: + detail_url_regex = r'^{prefix}{trailing_slash}$' + # Detail route. + ret.append(routers.Route( + url=detail_url_regex, + mapping={ + 'get': 'retrieve', + 'put': 'update', + 'patch': 'partial_update', + 'delete': 'destroy' + }, + name='{basename}-detail', + detail=True, + initkwargs={'suffix': 'Instance'} + )) + + return ret + + def get_lookup_regex(self, viewset, lookup_prefix=''): + lookup_fields = getattr(viewset, 'lookup_fields', None) + if lookup_fields: + base_regex = '(?P<{lookup_prefix}{lookup_url_kwarg}>[^/.]+)' + return '/'.join(map( + lambda x: base_regex.format( + lookup_prefix=lookup_prefix, + lookup_url_kwarg=x), + lookup_fields)) + return super().get_lookup_regex(viewset, lookup_prefix) + + +router = Router() router.register('repository', RepositoryViewSet) router.register('repository-votes', RepositoryVotesViewSet) router.register('repositories', RepositoriesViewSet) From 5cad7f7607f717d6e5b1881632ce0362b8deb115 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Fri, 19 Jul 2019 13:44:16 -0300 Subject: [PATCH 071/207] Migration Change Password v1 to v2 and refact --- bothub/api/v1/views.py | 6 ++++ bothub/api/v2/account/permissions.py | 9 ++++++ bothub/api/v2/account/serializers.py | 16 ++++++++++ bothub/api/v2/account/views.py | 45 +++++++++++++++++++++++++++- bothub/api/v2/routers.py | 2 ++ 5 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 bothub/api/v2/account/permissions.py diff --git a/bothub/api/v1/views.py b/bothub/api/v1/views.py index db7b7d74..c4776f00 100644 --- a/bothub/api/v1/views.py +++ b/bothub/api/v1/views.py @@ -791,6 +791,12 @@ def create(self, request, *args, **kwargs): status.HTTP_201_CREATED if created else status.HTTP_200_OK) +@method_decorator( + name='update', + decorator=swagger_auto_schema( + deprecated=True + ), +) class ChangePasswordViewSet(GenericViewSet): """ Change current user password. diff --git a/bothub/api/v2/account/permissions.py b/bothub/api/v2/account/permissions.py new file mode 100644 index 00000000..8a7ecf39 --- /dev/null +++ b/bothub/api/v2/account/permissions.py @@ -0,0 +1,9 @@ +from rest_framework import permissions + + +class ChangePasswordPermission(permissions.BasePermission): + + def has_permission(self, request, view): + if request.user.check_password(request.data.get('password')): + return False + return True diff --git a/bothub/api/v2/account/serializers.py b/bothub/api/v2/account/serializers.py index 75f54483..fe4f2f22 100644 --- a/bothub/api/v2/account/serializers.py +++ b/bothub/api/v2/account/serializers.py @@ -45,3 +45,19 @@ class Meta: @staticmethod def validate_password(value): return make_password(value) + + +class ChangePasswordSerializer(serializers.ModelSerializer): + class Meta: + model = User + fields = [ + 'current_password', + 'password' + ] + ref_name = None + current_password = PasswordField( + required=True + ) + password = PasswordField( + required=True + ) diff --git a/bothub/api/v2/account/views.py b/bothub/api/v2/account/views.py index 403d423d..1f816d00 100644 --- a/bothub/api/v2/account/views.py +++ b/bothub/api/v2/account/views.py @@ -2,13 +2,17 @@ from rest_framework.viewsets import GenericViewSet from rest_framework.response import Response from rest_framework.authtoken.models import Token -from rest_framework import status, mixins +from rest_framework import status, mixins, exceptions +from rest_framework import permissions from drf_yasg.utils import swagger_auto_schema + +from bothub.api.v2.account.permissions import ChangePasswordPermission from bothub.api.v2.metadata import Metadata from bothub.authentication.models import User from .serializers import LoginSerializer from .serializers import RegisterUserSerializer +from .serializers import ChangePasswordSerializer @method_decorator( @@ -52,3 +56,42 @@ class RegisterUserViewSet( serializer_class = RegisterUserSerializer lookup_field = ('email', 'name', 'nickname', 'password') metadata_class = Metadata + + +class ChangePasswordViewSet(mixins.UpdateModelMixin, GenericViewSet): + """ + Change current user password. + """ + serializer_class = ChangePasswordSerializer + queryset = User.objects + lookup_field = None + permission_classes = [ + permissions.IsAuthenticated, + ChangePasswordPermission + ] + metadata_class = Metadata + + def permission_denied(self, request, message=None): + raise exceptions.PermissionDenied(detail='Wrong password') + + def get_object(self, *args, **kwargs): + request = self.request + user = request.user + + # May raise a permission denied + self.check_object_permissions(self.request, user) + + return user + + def update(self, request, *args, **kwargs): + self.object = self.get_object() + serializer = self.get_serializer(data=request.data) + + if serializer.is_valid(): + self.object.set_password(serializer.data.get('password')) + self.object.save() + return Response({}, status=status.HTTP_200_OK) + + return Response( + serializer.errors, + status=status.HTTP_400_BAD_REQUEST) diff --git a/bothub/api/v2/routers.py b/bothub/api/v2/routers.py index f49d1aa0..ecdb7288 100644 --- a/bothub/api/v2/routers.py +++ b/bothub/api/v2/routers.py @@ -9,6 +9,7 @@ from .evaluate.views import ResultsListViewSet from .account.views import LoginViewSet from .account.views import RegisterUserViewSet +from .account.views import ChangePasswordViewSet class Router(routers.SimpleRouter): @@ -90,3 +91,4 @@ def get_lookup_regex(self, viewset, lookup_prefix=''): router.register('evaluate', EvaluateViewSet) router.register('account/login', LoginViewSet) router.register('account/register', RegisterUserViewSet) +router.register('account/change-password', ChangePasswordViewSet) From 328c2b0aeff10335dd3334b6bcfa402cab83b43d Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Fri, 19 Jul 2019 14:11:35 -0300 Subject: [PATCH 072/207] Migration Forgot-Password v1 to v2 and refact --- bothub/api/v1/views.py | 6 +++++ bothub/api/v2/account/permissions.py | 9 +++++++ bothub/api/v2/account/serializers.py | 35 ++++++++++++++++++++-------- bothub/api/v2/account/views.py | 35 ++++++++++++++++++++++++++++ bothub/api/v2/routers.py | 2 ++ 5 files changed, 77 insertions(+), 10 deletions(-) diff --git a/bothub/api/v1/views.py b/bothub/api/v1/views.py index c4776f00..5c43d2c2 100644 --- a/bothub/api/v1/views.py +++ b/bothub/api/v1/views.py @@ -831,6 +831,12 @@ def update(self, request, *args, **kwargs): status=status.HTTP_400_BAD_REQUEST) +@method_decorator( + name='create', + decorator=swagger_auto_schema( + deprecated=True + ), +) class RequestResetPassword(GenericViewSet): """ Request reset password diff --git a/bothub/api/v2/account/permissions.py b/bothub/api/v2/account/permissions.py index 8a7ecf39..2cbee900 100644 --- a/bothub/api/v2/account/permissions.py +++ b/bothub/api/v2/account/permissions.py @@ -1,4 +1,5 @@ from rest_framework import permissions +from bothub.authentication.models import User class ChangePasswordPermission(permissions.BasePermission): @@ -7,3 +8,11 @@ def has_permission(self, request, view): if request.user.check_password(request.data.get('password')): return False return True + + +class RequestResetPasswordPermission(permissions.BasePermission): + + def has_permission(self, request, view): + if User.objects.filter(email=request.data.get('email')).count() == 0: + return False + return True diff --git a/bothub/api/v2/account/serializers.py b/bothub/api/v2/account/serializers.py index fe4f2f22..1731fd85 100644 --- a/bothub/api/v2/account/serializers.py +++ b/bothub/api/v2/account/serializers.py @@ -26,6 +26,12 @@ class Meta: class RegisterUserSerializer(serializers.ModelSerializer): + password = PasswordField( + write_only=True, + validators=[ + validate_password, + ]) + class Meta: model = User fields = [ @@ -36,18 +42,19 @@ class Meta: ] ref_name = None - password = PasswordField( - write_only=True, - validators=[ - validate_password, - ]) - @staticmethod def validate_password(value): return make_password(value) class ChangePasswordSerializer(serializers.ModelSerializer): + current_password = PasswordField( + required=True + ) + password = PasswordField( + required=True + ) + class Meta: model = User fields = [ @@ -55,9 +62,17 @@ class Meta: 'password' ] ref_name = None - current_password = PasswordField( - required=True - ) - password = PasswordField( + + +class RequestResetPasswordSerializer(serializers.ModelSerializer): + email = serializers.EmailField( + label=_('Email'), required=True ) + + class Meta: + model = User + fields = [ + 'email' + ] + ref_name = None diff --git a/bothub/api/v2/account/views.py b/bothub/api/v2/account/views.py index 1f816d00..44d6cf84 100644 --- a/bothub/api/v2/account/views.py +++ b/bothub/api/v2/account/views.py @@ -7,12 +7,14 @@ from drf_yasg.utils import swagger_auto_schema from bothub.api.v2.account.permissions import ChangePasswordPermission +from bothub.api.v2.account.permissions import RequestResetPasswordPermission from bothub.api.v2.metadata import Metadata from bothub.authentication.models import User from .serializers import LoginSerializer from .serializers import RegisterUserSerializer from .serializers import ChangePasswordSerializer +from .serializers import RequestResetPasswordSerializer @method_decorator( @@ -95,3 +97,36 @@ def update(self, request, *args, **kwargs): return Response( serializer.errors, status=status.HTTP_400_BAD_REQUEST) + + +class RequestResetPasswordViewSet(mixins.CreateModelMixin, GenericViewSet): + """ + Request reset password + """ + serializer_class = RequestResetPasswordSerializer + queryset = User.objects + lookup_field = ['email'] + permission_classes = [ + permissions.AllowAny, + RequestResetPasswordPermission + ] + metadata_class = Metadata + + def permission_denied(self, request, message=None): + raise exceptions.PermissionDenied( + detail='No user registered with this email' + ) + + def get_object(self): + return self.queryset.get(email=self.request.data.get('email')) + + def create(self, request, *args, **kwargs): + serializer = self.get_serializer(data=request.data) + if serializer.is_valid(): + self.object = self.get_object() + self.object.send_reset_password_email() + return Response({}) + return Response( + serializer.errors, + status=status.HTTP_400_BAD_REQUEST) + diff --git a/bothub/api/v2/routers.py b/bothub/api/v2/routers.py index ecdb7288..b815992c 100644 --- a/bothub/api/v2/routers.py +++ b/bothub/api/v2/routers.py @@ -10,6 +10,7 @@ from .account.views import LoginViewSet from .account.views import RegisterUserViewSet from .account.views import ChangePasswordViewSet +from .account.views import RequestResetPasswordViewSet class Router(routers.SimpleRouter): @@ -92,3 +93,4 @@ def get_lookup_regex(self, viewset, lookup_prefix=''): router.register('account/login', LoginViewSet) router.register('account/register', RegisterUserViewSet) router.register('account/change-password', ChangePasswordViewSet) +router.register('account/forgot-password', RequestResetPasswordViewSet) From 9d789f45e54ce60a4ef27c2ca4e78bae26d3a82f Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Sat, 20 Jul 2019 10:47:56 -0300 Subject: [PATCH 073/207] [fix] Permissions v2 --- bothub/api/v2/account/permissions.py | 18 ------------------ bothub/api/v2/account/serializers.py | 19 ++++++++++++++++++- bothub/api/v2/account/views.py | 21 +++------------------ 3 files changed, 21 insertions(+), 37 deletions(-) delete mode 100644 bothub/api/v2/account/permissions.py diff --git a/bothub/api/v2/account/permissions.py b/bothub/api/v2/account/permissions.py deleted file mode 100644 index 2cbee900..00000000 --- a/bothub/api/v2/account/permissions.py +++ /dev/null @@ -1,18 +0,0 @@ -from rest_framework import permissions -from bothub.authentication.models import User - - -class ChangePasswordPermission(permissions.BasePermission): - - def has_permission(self, request, view): - if request.user.check_password(request.data.get('password')): - return False - return True - - -class RequestResetPasswordPermission(permissions.BasePermission): - - def has_permission(self, request, view): - if User.objects.filter(email=request.data.get('email')).count() == 0: - return False - return True diff --git a/bothub/api/v2/account/serializers.py b/bothub/api/v2/account/serializers.py index 1731fd85..d04c2739 100644 --- a/bothub/api/v2/account/serializers.py +++ b/bothub/api/v2/account/serializers.py @@ -3,6 +3,7 @@ from django.contrib.auth.hashers import make_password from rest_framework.authtoken.serializers import AuthTokenSerializer from rest_framework import serializers +from rest_framework.exceptions import ValidationError from bothub.authentication.models import User from ..fields import PasswordField @@ -52,7 +53,10 @@ class ChangePasswordSerializer(serializers.ModelSerializer): required=True ) password = PasswordField( - required=True + required=True, + validators=[ + validate_password, + ] ) class Meta: @@ -63,6 +67,12 @@ class Meta: ] ref_name = None + def validate_current_password(self, value): + request = self.context.get('request') + if not request.user.check_password(value): + raise ValidationError(_('Wrong password')) + return value + class RequestResetPasswordSerializer(serializers.ModelSerializer): email = serializers.EmailField( @@ -76,3 +86,10 @@ class Meta: 'email' ] ref_name = None + + def validate_email(self, value): + try: + User.objects.get(email=value) + return value + except User.DoesNotExist: + raise ValidationError(_('No user registered with this email')) diff --git a/bothub/api/v2/account/views.py b/bothub/api/v2/account/views.py index 44d6cf84..0753d47c 100644 --- a/bothub/api/v2/account/views.py +++ b/bothub/api/v2/account/views.py @@ -2,12 +2,9 @@ from rest_framework.viewsets import GenericViewSet from rest_framework.response import Response from rest_framework.authtoken.models import Token -from rest_framework import status, mixins, exceptions +from rest_framework import status, mixins from rest_framework import permissions from drf_yasg.utils import swagger_auto_schema - -from bothub.api.v2.account.permissions import ChangePasswordPermission -from bothub.api.v2.account.permissions import RequestResetPasswordPermission from bothub.api.v2.metadata import Metadata from bothub.authentication.models import User @@ -69,13 +66,10 @@ class ChangePasswordViewSet(mixins.UpdateModelMixin, GenericViewSet): lookup_field = None permission_classes = [ permissions.IsAuthenticated, - ChangePasswordPermission + # ChangePasswordPermission ] metadata_class = Metadata - def permission_denied(self, request, message=None): - raise exceptions.PermissionDenied(detail='Wrong password') - def get_object(self, *args, **kwargs): request = self.request user = request.user @@ -106,17 +100,9 @@ class RequestResetPasswordViewSet(mixins.CreateModelMixin, GenericViewSet): serializer_class = RequestResetPasswordSerializer queryset = User.objects lookup_field = ['email'] - permission_classes = [ - permissions.AllowAny, - RequestResetPasswordPermission - ] + permission_classes = [permissions.AllowAny] metadata_class = Metadata - def permission_denied(self, request, message=None): - raise exceptions.PermissionDenied( - detail='No user registered with this email' - ) - def get_object(self): return self.queryset.get(email=self.request.data.get('email')) @@ -129,4 +115,3 @@ def create(self, request, *args, **kwargs): return Response( serializer.errors, status=status.HTTP_400_BAD_REQUEST) - From 6e811908a9f5411d98a4b943a8392c1f07d4f086 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Sat, 20 Jul 2019 18:03:44 -0300 Subject: [PATCH 074/207] Migration User-Profile v1 to v2 and refact --- bothub/api/v1/views.py | 24 ++++++++++++++++++++++++ bothub/api/v2/account/serializers.py | 11 +++++++++++ bothub/api/v2/account/views.py | 16 ++++++++++++++++ bothub/api/v2/routers.py | 2 ++ 4 files changed, 53 insertions(+) diff --git a/bothub/api/v1/views.py b/bothub/api/v1/views.py index 5c43d2c2..fb39479f 100644 --- a/bothub/api/v1/views.py +++ b/bothub/api/v1/views.py @@ -878,6 +878,24 @@ def update(self, request, *args, **kwargs): status=status.HTTP_400_BAD_REQUEST) +@method_decorator( + name='update', + decorator=swagger_auto_schema( + deprecated=True + ), +) +@method_decorator( + name='retrieve', + decorator=swagger_auto_schema( + deprecated=True + ), +) +@method_decorator( + name='partial_update', + decorator=swagger_auto_schema( + deprecated=True + ), +) class MyUserProfileViewSet( mixins.RetrieveModelMixin, mixins.UpdateModelMixin, @@ -911,6 +929,12 @@ def get_object(self, *args, **kwargs): return user +@method_decorator( + name='retrieve', + decorator=swagger_auto_schema( + deprecated=True + ), +) class UserProfileViewSet( mixins.RetrieveModelMixin, GenericViewSet): diff --git a/bothub/api/v2/account/serializers.py b/bothub/api/v2/account/serializers.py index d04c2739..25db3730 100644 --- a/bothub/api/v2/account/serializers.py +++ b/bothub/api/v2/account/serializers.py @@ -93,3 +93,14 @@ def validate_email(self, value): return value except User.DoesNotExist: raise ValidationError(_('No user registered with this email')) + + +class UserSerializer(serializers.ModelSerializer): + class Meta: + model = User + fields = [ + 'nickname', + 'name', + 'locale', + ] + ref_name = None diff --git a/bothub/api/v2/account/views.py b/bothub/api/v2/account/views.py index 0753d47c..ed2f4f55 100644 --- a/bothub/api/v2/account/views.py +++ b/bothub/api/v2/account/views.py @@ -12,6 +12,7 @@ from .serializers import RegisterUserSerializer from .serializers import ChangePasswordSerializer from .serializers import RequestResetPasswordSerializer +from .serializers import UserSerializer @method_decorator( @@ -115,3 +116,18 @@ def create(self, request, *args, **kwargs): return Response( serializer.errors, status=status.HTTP_400_BAD_REQUEST) + + +class UserProfileViewSet( + mixins.RetrieveModelMixin, + mixins.UpdateModelMixin, + GenericViewSet): + """ + Get user profile + """ + serializer_class = UserSerializer + queryset = User.objects + lookup_field = 'nickname' + permission_classes = [ + permissions.IsAuthenticatedOrReadOnly + ] diff --git a/bothub/api/v2/routers.py b/bothub/api/v2/routers.py index b815992c..1a62b485 100644 --- a/bothub/api/v2/routers.py +++ b/bothub/api/v2/routers.py @@ -11,6 +11,7 @@ from .account.views import RegisterUserViewSet from .account.views import ChangePasswordViewSet from .account.views import RequestResetPasswordViewSet +from .account.views import UserProfileViewSet class Router(routers.SimpleRouter): @@ -94,3 +95,4 @@ def get_lookup_regex(self, viewset, lookup_prefix=''): router.register('account/register', RegisterUserViewSet) router.register('account/change-password', ChangePasswordViewSet) router.register('account/forgot-password', RequestResetPasswordViewSet) +router.register('account/user-profile', UserProfileViewSet) From 83f0c7de757d0a6d5daa03ba7413cf53adeadc47 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Sat, 20 Jul 2019 18:13:43 -0300 Subject: [PATCH 075/207] Migrate Search-User v1 to v2 and refact --- bothub/api/v1/views.py | 6 ++++++ bothub/api/v2/account/views.py | 29 +++++++++++++++++++++++++++++ bothub/api/v2/routers.py | 2 ++ 3 files changed, 37 insertions(+) diff --git a/bothub/api/v1/views.py b/bothub/api/v1/views.py index fb39479f..6f01fcbe 100644 --- a/bothub/api/v1/views.py +++ b/bothub/api/v1/views.py @@ -1082,6 +1082,12 @@ def update(self, *args, **kwargs): return response +@method_decorator( + name='list', + decorator=swagger_auto_schema( + deprecated=True, + ) +) class SearchUserViewSet( mixins.ListModelMixin, GenericViewSet): diff --git a/bothub/api/v2/account/views.py b/bothub/api/v2/account/views.py index ed2f4f55..460e6822 100644 --- a/bothub/api/v2/account/views.py +++ b/bothub/api/v2/account/views.py @@ -1,4 +1,6 @@ from django.utils.decorators import method_decorator +from django_filters.rest_framework import DjangoFilterBackend +from rest_framework.filters import SearchFilter from rest_framework.viewsets import GenericViewSet from rest_framework.response import Response from rest_framework.authtoken.models import Token @@ -131,3 +133,30 @@ class UserProfileViewSet( permission_classes = [ permissions.IsAuthenticatedOrReadOnly ] + + +class SearchUserViewSet( + mixins.ListModelMixin, + GenericViewSet): + serializer_class = UserSerializer + queryset = User.objects.all() + filter_backends = [ + DjangoFilterBackend, + SearchFilter, + ] + search_fields = [ + '=name', + '^name', + '$name', + '=nickname', + '^nickname', + '$nickname', + '=email', + ] + pagination_class = None + limit = 5 + + def list(self, request, *args, **kwargs): + queryset = self.filter_queryset(self.get_queryset())[:self.limit] + serializer = self.get_serializer(queryset, many=True) + return Response(serializer.data) diff --git a/bothub/api/v2/routers.py b/bothub/api/v2/routers.py index 1a62b485..cb47cf50 100644 --- a/bothub/api/v2/routers.py +++ b/bothub/api/v2/routers.py @@ -12,6 +12,7 @@ from .account.views import ChangePasswordViewSet from .account.views import RequestResetPasswordViewSet from .account.views import UserProfileViewSet +from .account.views import SearchUserViewSet class Router(routers.SimpleRouter): @@ -96,3 +97,4 @@ def get_lookup_regex(self, viewset, lookup_prefix=''): router.register('account/change-password', ChangePasswordViewSet) router.register('account/forgot-password', RequestResetPasswordViewSet) router.register('account/user-profile', UserProfileViewSet) +router.register('account/search-user', SearchUserViewSet) From fb22dc267e631f87532541440cdc1bf9e7bb00f0 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Sat, 20 Jul 2019 18:22:09 -0300 Subject: [PATCH 076/207] Migration Reset-Password v1 to v2 and refact --- bothub/api/v2/account/serializers.py | 27 +++++++++++++++++++++++++++ bothub/api/v2/account/views.py | 25 ++++++++++++++++++++++--- bothub/api/v2/routers.py | 2 ++ 3 files changed, 51 insertions(+), 3 deletions(-) diff --git a/bothub/api/v2/account/serializers.py b/bothub/api/v2/account/serializers.py index 25db3730..8b458ce6 100644 --- a/bothub/api/v2/account/serializers.py +++ b/bothub/api/v2/account/serializers.py @@ -104,3 +104,30 @@ class Meta: 'locale', ] ref_name = None + + +class ResetPasswordSerializer(serializers.ModelSerializer): + token = serializers.CharField( + label=_('Token'), + style={'show': False} + ) + password = PasswordField( + label=_('New Password'), + required=True, + validators=[ + validate_password, + ]) + + class Meta: + model = User + fields = [ + 'token', + 'password', + ] + ref_name = None + + def validate_token(self, value): + user = self.context.get('view').get_object() + if not user.check_password_reset_token(value): + raise ValidationError(_('Invalid token for this user')) + return value diff --git a/bothub/api/v2/account/views.py b/bothub/api/v2/account/views.py index 460e6822..79a12871 100644 --- a/bothub/api/v2/account/views.py +++ b/bothub/api/v2/account/views.py @@ -15,6 +15,7 @@ from .serializers import ChangePasswordSerializer from .serializers import RequestResetPasswordSerializer from .serializers import UserSerializer +from .serializers import ResetPasswordSerializer @method_decorator( @@ -135,9 +136,7 @@ class UserProfileViewSet( ] -class SearchUserViewSet( - mixins.ListModelMixin, - GenericViewSet): +class SearchUserViewSet(mixins.ListModelMixin, GenericViewSet): serializer_class = UserSerializer queryset = User.objects.all() filter_backends = [ @@ -160,3 +159,23 @@ def list(self, request, *args, **kwargs): queryset = self.filter_queryset(self.get_queryset())[:self.limit] serializer = self.get_serializer(queryset, many=True) return Response(serializer.data) + + +class ResetPasswordViewSet(GenericViewSet): + """ + Reset password + """ + serializer_class = ResetPasswordSerializer + queryset = User.objects + lookup_field = 'nickname' + + def update(self, request, *args, **kwargs): + self.object = self.get_object() + serializer = self.get_serializer(data=request.data) + if serializer.is_valid(): + self.object.set_password(serializer.data.get('password')) + self.object.save() + return Response({}) + return Response( + serializer.errors, + status=status.HTTP_400_BAD_REQUEST) diff --git a/bothub/api/v2/routers.py b/bothub/api/v2/routers.py index cb47cf50..80147f87 100644 --- a/bothub/api/v2/routers.py +++ b/bothub/api/v2/routers.py @@ -13,6 +13,7 @@ from .account.views import RequestResetPasswordViewSet from .account.views import UserProfileViewSet from .account.views import SearchUserViewSet +from .account.views import ResetPasswordViewSet class Router(routers.SimpleRouter): @@ -98,3 +99,4 @@ def get_lookup_regex(self, viewset, lookup_prefix=''): router.register('account/forgot-password', RequestResetPasswordViewSet) router.register('account/user-profile', UserProfileViewSet) router.register('account/search-user', SearchUserViewSet) +router.register('account/reset-password', ResetPasswordViewSet) From 34683a7dde3ce95def6655177964077ffd8058fb Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Sat, 20 Jul 2019 18:24:11 -0300 Subject: [PATCH 077/207] Update Reset-Password --- bothub/api/v1/views.py | 6 ++++++ bothub/api/v2/account/views.py | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/bothub/api/v1/views.py b/bothub/api/v1/views.py index 6f01fcbe..8f15eb62 100644 --- a/bothub/api/v1/views.py +++ b/bothub/api/v1/views.py @@ -858,6 +858,12 @@ def create(self, request, *args, **kwargs): status=status.HTTP_400_BAD_REQUEST) +@method_decorator( + name='update', + decorator=swagger_auto_schema( + deprecated=True + ), +) class ResetPassword(GenericViewSet): """ Reset password diff --git a/bothub/api/v2/account/views.py b/bothub/api/v2/account/views.py index 79a12871..f2b71327 100644 --- a/bothub/api/v2/account/views.py +++ b/bothub/api/v2/account/views.py @@ -161,7 +161,7 @@ def list(self, request, *args, **kwargs): return Response(serializer.data) -class ResetPasswordViewSet(GenericViewSet): +class ResetPasswordViewSet(mixins.UpdateModelMixin, GenericViewSet): """ Reset password """ From e4d7bcba024b935e5235d04b34cf74e6fba5c8aa Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Sat, 20 Jul 2019 18:45:32 -0300 Subject: [PATCH 078/207] Account tests --- bothub/api/v2/account/views.py | 3 +- bothub/api/v2/tests/test_account.py | 347 ++++++++++++++++++++++++++++ 2 files changed, 348 insertions(+), 2 deletions(-) create mode 100644 bothub/api/v2/tests/test_account.py diff --git a/bothub/api/v2/account/views.py b/bothub/api/v2/account/views.py index f2b71327..3cec556a 100644 --- a/bothub/api/v2/account/views.py +++ b/bothub/api/v2/account/views.py @@ -69,8 +69,7 @@ class ChangePasswordViewSet(mixins.UpdateModelMixin, GenericViewSet): queryset = User.objects lookup_field = None permission_classes = [ - permissions.IsAuthenticated, - # ChangePasswordPermission + permissions.IsAuthenticated ] metadata_class = Metadata diff --git a/bothub/api/v2/tests/test_account.py b/bothub/api/v2/tests/test_account.py new file mode 100644 index 00000000..bbb12021 --- /dev/null +++ b/bothub/api/v2/tests/test_account.py @@ -0,0 +1,347 @@ +import json + +from django.test import TestCase +from django.test import RequestFactory +from django.test.client import MULTIPART_CONTENT +from rest_framework import status + +from bothub.authentication.models import User + +from ..account.views import RegisterUserViewSet +from ..account.views import LoginViewSet +from ..account.views import ChangePasswordViewSet +from ..account.views import RequestResetPasswordViewSet +from ..account.views import ResetPasswordViewSet +from ..account.views import UserProfileViewSet + +from .utils import create_user_and_token + + +class LoginTestCase(TestCase): + def setUp(self): + self.factory = RequestFactory() + + self.password = 'abcgq!!123' + self.email = 'user@user.com' + + user = User.objects.create( + email=self.email, + nickname='user', + name='User') + user.set_password(self.password) + user.save(update_fields=['password']) + + def request(self, data): + request = self.factory.post( + '/v2/account/login/', + data) + response = LoginViewSet.as_view( + {'post': 'create'})(request) + response.render() + content_data = json.loads(response.content) + return (response, content_data,) + + def test_okay(self): + response, content_data = self.request({ + 'username': self.email, + 'password': self.password, + }) + self.assertEqual( + response.status_code, + status.HTTP_201_CREATED) + self.assertIn( + 'token', + content_data.keys()) + + def test_wrong_password(self): + response, content_data = self.request({ + 'username': self.email, + 'password': 'wrong', + }) + self.assertEqual( + response.status_code, + status.HTTP_400_BAD_REQUEST) + + +class RegisterUserTestCase(TestCase): + def setUp(self): + self.factory = RequestFactory() + + def request(self, data): + request = self.factory.post( + '/v2/account/register/', + data) + response = RegisterUserViewSet.as_view( + {'post': 'create'})(request) + response.render() + content_data = json.loads(response.content) + return (response, content_data,) + + def test_okay(self): + email = 'fake@user.com' + password = 'abc!1234' + response, content_data = self.request({ + 'email': email, + 'name': 'Fake', + 'nickname': 'fake', + 'password': password, + }) + self.assertEqual( + response.status_code, + status.HTTP_201_CREATED) + user = User.objects.get(email=email) + self.assertTrue(user.check_password(password)) + + def test_invalid_password(self): + response, content_data = self.request({ + 'email': 'fake@user.com', + 'name': 'Fake', + 'nickname': 'fake', + 'password': 'abc', + }) + self.assertEqual( + response.status_code, + status.HTTP_400_BAD_REQUEST) + self.assertIn( + 'password', + content_data.keys()) + + def test_unique_nickname(self): + nickname = 'fake' + User.objects.create_user('user1@user.com', nickname) + response, content_data = self.request({ + 'email': 'user2@user.com', + 'name': 'Fake', + 'nickname': nickname, + 'password': 'abc!1234', + }) + self.assertEqual( + response.status_code, + status.HTTP_400_BAD_REQUEST) + self.assertIn( + 'nickname', + content_data.keys()) + + def test_invalid_nickname_url_conflict(self): + URL_PATHS = [ + 'api', + 'docs', + 'admin', + ] + + for url_path in URL_PATHS: + response, content_data = self.request({ + 'email': '{}@fake.com'.format(url_path), + 'name': 'Fake', + 'nickname': url_path, + 'password': 'abc!1234', + }) + + self.assertEqual( + response.status_code, + status.HTTP_400_BAD_REQUEST) + self.assertIn( + 'nickname', + content_data.keys()) + + +class RequestResetPasswordTestCase(TestCase): + def setUp(self): + self.factory = RequestFactory() + + self.email = 'user@user.com' + + User.objects.create( + email=self.email, + nickname='user', + name='User') + + def request(self, data): + request = self.factory.post( + '/v2/account/forgot-password/', + data) + response = RequestResetPasswordViewSet.as_view( + {'post': 'create'})(request) + response.render() + content_data = json.loads(response.content) + return (response, content_data,) + + def test_okay(self): + response, content_data = self.request({ + 'email': self.email, + }) + + def test_email_not_found(self): + response, content_data = self.request({ + 'email': 'nouser@fake.com', + }) + self.assertEqual( + response.status_code, + status.HTTP_400_BAD_REQUEST) + self.assertIn( + 'email', + content_data.keys()) + + +class ResetPasswordTestCase(TestCase): + def setUp(self): + self.factory = RequestFactory() + + self.user = User.objects.create( + email='user@user.com', + nickname='user', + name='User') + self.reset_password_token = self.user.make_password_reset_token() + + def request(self, nickname, data): + request = self.factory.post( + '/v2/account/reset-password/{}/'.format(nickname), + data) + response = ResetPasswordViewSet.as_view( + {'post': 'update'})(request, nickname=nickname) + response.render() + content_data = json.loads(response.content) + return (response, content_data,) + + def test_okay(self): + new_password = 'valid12!' + response, content_data = self.request( + self.user.nickname, + { + 'token': self.reset_password_token, + 'password': new_password, + }) + self.assertEqual( + response.status_code, + status.HTTP_200_OK) + self.user = User.objects.get(pk=self.user.pk) + self.assertTrue(self.user.check_password(new_password)) + + def test_invalid_token(self): + response, content_data = self.request( + self.user.nickname, + { + 'token': '112233', + 'password': 'valid12!', + }) + self.assertEqual( + response.status_code, + status.HTTP_400_BAD_REQUEST) + self.assertIn( + 'token', + content_data.keys()) + + +class ChangePasswordTestCase(TestCase): + def setUp(self): + self.factory = RequestFactory() + self.user, self.user_token = create_user_and_token() + self.password = '12555q!66' + self.user.set_password(self.password) + self.user.save(update_fields=['password']) + + def request(self, data, token): + authorization_header = { + 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), + } + request = self.factory.post( + '/v2/account/change-password/', + data, + **authorization_header) + response = ChangePasswordViewSet.as_view( + {'post': 'update'})(request) + response.render() + content_data = json.loads(response.content) + return (response, content_data,) + + def test_okay(self): + new_password = 'kkl8&!qq' + response, content_data = self.request( + { + 'current_password': self.password, + 'password': new_password, + }, + self.user_token) + self.assertEqual( + response.status_code, + status.HTTP_200_OK) + + def test_wrong_password(self): + response, content_data = self.request( + { + 'current_password': 'wrong_password', + 'password': 'new_password', + }, + self.user_token) + self.assertEqual( + response.status_code, + status.HTTP_400_BAD_REQUEST) + self.assertIn( + 'current_password', + content_data.keys()) + + +class ListUserProfileTestCase(TestCase): + def setUp(self): + self.factory = RequestFactory() + self.user, self.user_token = create_user_and_token() + + def request(self, token): + request = self.factory.get( + '/v2/account/user-profile/{}/'.format(self.user.nickname) + ) + response = UserProfileViewSet.as_view( + {'get': 'retrieve'})(request) + response.render() + content_data = json.loads(response.content) + return (response, content_data,) + + def test_okay(self): + response, content_data = self.request(self.user_token) + self.assertEqual( + response.status_code, + status.HTTP_200_OK) + self.assertEqual( + content_data.get('nickname'), + self.user.nickname) + + +class UserUpdateTestCase(TestCase): + def setUp(self): + self.factory = RequestFactory() + self.user, self.user_token = create_user_and_token() + + def request(self, user, data, token): + authorization_header = { + 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), + } + request = self.factory.patch( + '/v2/account/user-profile/{}/'.format(self.user.nickname), + self.factory._encode_data(data, MULTIPART_CONTENT), + MULTIPART_CONTENT, + **authorization_header) + response = UserProfileViewSet.as_view( + {'patch': 'update'})( + request, + pk=user.pk, + nickname=user.nickname, + partial=True + ) + response.render() + content_data = json.loads(response.content) + return (response, content_data,) + + def test_okay(self): + new_locale = 'Maceió - Alagoas' + response, content_data = self.request( + self.user, + { + 'locale': new_locale, + }, + self.user_token) + self.assertEqual( + response.status_code, + status.HTTP_200_OK) + self.assertEqual( + content_data.get('locale'), + new_locale) From 25b26988fb31f76736599bbb6efdabbe1b152890 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Sat, 20 Jul 2019 18:49:22 -0300 Subject: [PATCH 079/207] [fix] Test List User Profile --- bothub/api/v2/tests/test_account.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bothub/api/v2/tests/test_account.py b/bothub/api/v2/tests/test_account.py index bbb12021..b28da267 100644 --- a/bothub/api/v2/tests/test_account.py +++ b/bothub/api/v2/tests/test_account.py @@ -291,7 +291,7 @@ def request(self, token): '/v2/account/user-profile/{}/'.format(self.user.nickname) ) response = UserProfileViewSet.as_view( - {'get': 'retrieve'})(request) + {'get': 'retrieve'})(request, nickname=self.user.nickname) response.render() content_data = json.loads(response.content) return (response, content_data,) From 0ba5e681d94deace9f2db5abb6d24921e817d497 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Tue, 23 Jul 2019 08:54:53 -0300 Subject: [PATCH 080/207] Added test list user profile not exists --- Pipfile.lock | 6 +++--- bothub/api/v2/tests/test_account.py | 20 ++++++++++++++++---- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/Pipfile.lock b/Pipfile.lock index 616240ea..a6675b6f 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -408,10 +408,10 @@ }, "pyparsing": { "hashes": [ - "sha256:1873c03321fc118f4e9746baf201ff990ceb915f433f23b395f5580d1840cb2a", - "sha256:9b6323ef4ab914af344ba97510e966d64ba91055d6b9afa6b30799340e89cc03" + "sha256:530d8bf8cc93a34019d08142593cf4d78a05c890da8cf87ffa3120af53772238", + "sha256:f78e99616b6f1a4745c0580e170251ef1bbafc0d0513e270c4bd281bf29d2800" ], - "version": "==2.4.0" + "version": "==2.4.1" }, "six": { "hashes": [ diff --git a/bothub/api/v2/tests/test_account.py b/bothub/api/v2/tests/test_account.py index b28da267..79f5077d 100644 --- a/bothub/api/v2/tests/test_account.py +++ b/bothub/api/v2/tests/test_account.py @@ -286,18 +286,21 @@ def setUp(self): self.factory = RequestFactory() self.user, self.user_token = create_user_and_token() - def request(self, token): + def request(self, token, nickname): request = self.factory.get( - '/v2/account/user-profile/{}/'.format(self.user.nickname) + '/v2/account/user-profile/{}/'.format(nickname) ) response = UserProfileViewSet.as_view( - {'get': 'retrieve'})(request, nickname=self.user.nickname) + {'get': 'retrieve'})(request, nickname=nickname) response.render() content_data = json.loads(response.content) return (response, content_data,) def test_okay(self): - response, content_data = self.request(self.user_token) + response, content_data = self.request( + self.user_token, + self.user.nickname + ) self.assertEqual( response.status_code, status.HTTP_200_OK) @@ -305,6 +308,15 @@ def test_okay(self): content_data.get('nickname'), self.user.nickname) + def test_not_exists(self): + response, content_data = self.request(self.user_token, 'no_exists') + self.assertEqual( + response.status_code, + status.HTTP_404_NOT_FOUND) + self.assertEqual( + content_data.get('detail'), + 'Not found.') + class UserUpdateTestCase(TestCase): def setUp(self): From 4cb735cc12906e3ec096e3493559a9cae7d5a475 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Tue, 23 Jul 2019 10:05:45 -0300 Subject: [PATCH 081/207] Update status_code Response --- bothub/api/v2/account/views.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bothub/api/v2/account/views.py b/bothub/api/v2/account/views.py index 3cec556a..c79c3b18 100644 --- a/bothub/api/v2/account/views.py +++ b/bothub/api/v2/account/views.py @@ -89,7 +89,7 @@ def update(self, request, *args, **kwargs): if serializer.is_valid(): self.object.set_password(serializer.data.get('password')) self.object.save() - return Response({}, status=status.HTTP_200_OK) + return Response(status=status.HTTP_200_OK) return Response( serializer.errors, @@ -114,7 +114,7 @@ def create(self, request, *args, **kwargs): if serializer.is_valid(): self.object = self.get_object() self.object.send_reset_password_email() - return Response({}) + return Response(status=status.HTTP_201_CREATED) return Response( serializer.errors, status=status.HTTP_400_BAD_REQUEST) @@ -174,7 +174,7 @@ def update(self, request, *args, **kwargs): if serializer.is_valid(): self.object.set_password(serializer.data.get('password')) self.object.save() - return Response({}) + return Response(status=status.HTTP_200_OK) return Response( serializer.errors, status=status.HTTP_400_BAD_REQUEST) From b694a09a478919b4d305fb9c3d48a40dbb58fcd0 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Tue, 23 Jul 2019 10:15:12 -0300 Subject: [PATCH 082/207] [fix] Tests Account --- bothub/api/v2/tests/test_account.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bothub/api/v2/tests/test_account.py b/bothub/api/v2/tests/test_account.py index 79f5077d..aabfa3fe 100644 --- a/bothub/api/v2/tests/test_account.py +++ b/bothub/api/v2/tests/test_account.py @@ -163,7 +163,7 @@ def request(self, data): response = RequestResetPasswordViewSet.as_view( {'post': 'create'})(request) response.render() - content_data = json.loads(response.content) + content_data = json.loads(response.content or 'null') return (response, content_data,) def test_okay(self): @@ -200,7 +200,7 @@ def request(self, nickname, data): response = ResetPasswordViewSet.as_view( {'post': 'update'})(request, nickname=nickname) response.render() - content_data = json.loads(response.content) + content_data = json.loads(response.content or 'null') return (response, content_data,) def test_okay(self): @@ -251,7 +251,7 @@ def request(self, data, token): response = ChangePasswordViewSet.as_view( {'post': 'update'})(request) response.render() - content_data = json.loads(response.content) + content_data = json.loads(response.content or 'null') return (response, content_data,) def test_okay(self): From 2a38d107a9c1c0e6b6c39626992bf70b0e5732bc Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Tue, 23 Jul 2019 14:17:51 -0300 Subject: [PATCH 083/207] Update Doc to Swagger --- bothub/urls.py | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/bothub/urls.py b/bothub/urls.py index bf8d6459..9351c747 100644 --- a/bothub/urls.py +++ b/bothub/urls.py @@ -28,20 +28,16 @@ ) urlpatterns = [ - path('', include(bothub_api_routers.urls)), - path('api/', include(bothub_api_routers.urls)), + path('', schema_view.with_ui('swagger')), + path('v1/', include(bothub_api_routers.urls)), path('v2/', include(bothub_api_v2_urls)), - path('api/v2/', include(bothub_api_v2_urls)), - path('docs/', include_docs_urls(title='API Documentation')), path('admin/', admin.site.urls), path('ping/', ping, name='ping'), path('200/', r200, name='200'), path( 'downloadbotdata//', download_bot_data, - name='download_bot_data'), - re_path(r'^swagger(?P\.json|\.yaml)$', schema_view.without_ui()), - path('swagger/', schema_view.with_ui('swagger')) + name='download_bot_data') ] if settings.DEBUG: From 1b8063a9b127f4bf109eecee3dcf5ed6cb9272fd Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Tue, 23 Jul 2019 14:18:30 -0300 Subject: [PATCH 084/207] Update URL Tests --- bothub/api/v1/tests/test_authorization.py | 6 +++--- bothub/api/v1/tests/test_categories.py | 2 +- bothub/api/v1/tests/test_example.py | 10 +++++----- bothub/api/v1/tests/test_examples.py | 2 +- bothub/api/v1/tests/test_repository.py | 20 ++++++++++---------- bothub/api/v1/tests/test_request.py | 8 ++++---- bothub/api/v1/tests/test_translate.py | 8 ++++---- bothub/api/v1/tests/test_updates.py | 2 +- bothub/api/v1/tests/test_user.py | 14 +++++++------- bothub/api/v2/tests/test_evaluate.py | 12 ++++++------ bothub/api/v2/tests/test_examples.py | 2 +- bothub/api/v2/tests/test_repository.py | 22 +++++++++++----------- 12 files changed, 54 insertions(+), 54 deletions(-) diff --git a/bothub/api/v1/tests/test_authorization.py b/bothub/api/v1/tests/test_authorization.py index c3ef7dcd..24ab35e3 100644 --- a/bothub/api/v1/tests/test_authorization.py +++ b/bothub/api/v1/tests/test_authorization.py @@ -41,7 +41,7 @@ def request(self, repository, token): 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), } request = self.factory.get( - '/api/repository/{}/{}/'.format( + '/v1/repository/{}/{}/'.format( repository.owner.nickname, repository.slug), **authorization_header) @@ -118,7 +118,7 @@ def request(self, repository, token): 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), } request = self.factory.get( - '/api/list-authorizations/', + '/v1/list-authorizations/', { 'repository': repository.uuid, }, @@ -174,7 +174,7 @@ def request(self, repository, token, user, data): 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), } request = self.factory.patch( - '/api/authorization-role/{}/{}/'.format( + '/v1/authorization-role/{}/{}/'.format( repository.uuid, user.nickname), self.factory._encode_data(data, MULTIPART_CONTENT), MULTIPART_CONTENT, diff --git a/bothub/api/v1/tests/test_categories.py b/bothub/api/v1/tests/test_categories.py index 79f5c5ed..3de426df 100644 --- a/bothub/api/v1/tests/test_categories.py +++ b/bothub/api/v1/tests/test_categories.py @@ -18,7 +18,7 @@ def setUp(self): icon='business') def request(self): - request = self.factory.get('/api/categories/') + request = self.factory.get('/v1/categories/') response = Categories.as_view( {'get': 'list'})(request) response.render() diff --git a/bothub/api/v1/tests/test_example.py b/bothub/api/v1/tests/test_example.py index 9cd9b908..3c95e23b 100644 --- a/bothub/api/v1/tests/test_example.py +++ b/bothub/api/v1/tests/test_example.py @@ -36,7 +36,7 @@ def request(self, token, data): 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), } request = self.factory.post( - '/api/example/new/', + '/v1/example/new/', json.dumps(data), content_type='application/json', **authorization_header) @@ -373,7 +373,7 @@ def request(self, example, token): 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), } request = self.factory.get( - '/api/example/{}/'.format(example.id), + '/v1/example/{}/'.format(example.id), **authorization_header) response = RepositoryExampleViewSet.as_view( {'get': 'retrieve'})(request, pk=example.id) @@ -484,7 +484,7 @@ def request(self, example, token): 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), } request = self.factory.delete( - '/api/example/{}/'.format(example.id), + '/v1/example/{}/'.format(example.id), **authorization_header) response = RepositoryExampleViewSet.as_view( {'delete': 'destroy'})(request, pk=example.id) @@ -564,7 +564,7 @@ def request(self, example, token, data): 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), } request = self.factory.patch( - '/api/example/{}/'.format(example.id), + '/v1/example/{}/'.format(example.id), json.dumps(data), content_type='application/json', **authorization_header) @@ -635,7 +635,7 @@ def request(self, data, token): 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), } request = self.factory.get( - '/api/entities/', + '/v1/entities/', data=data, **authorization_header) response = RepositoryEntitiesViewSet.as_view( diff --git a/bothub/api/v1/tests/test_examples.py b/bothub/api/v1/tests/test_examples.py index 93499d65..69ea60d3 100644 --- a/bothub/api/v1/tests/test_examples.py +++ b/bothub/api/v1/tests/test_examples.py @@ -50,7 +50,7 @@ def request(self, data, token): 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), } request = self.factory.get( - '/api/examples/', + '/v1/examples/', data, **authorization_header) response = RepositoryExamplesViewSet.as_view( diff --git a/bothub/api/v1/tests/test_repository.py b/bothub/api/v1/tests/test_repository.py index 7194c993..920f124a 100644 --- a/bothub/api/v1/tests/test_repository.py +++ b/bothub/api/v1/tests/test_repository.py @@ -38,7 +38,7 @@ def setUp(self): def request(self, data): request = self.factory.post( - '/api/repository/new/', + '/v1/repository/new/', data, **self.authorization_header) response = NewRepositoryViewSet.as_view({'post': 'create'})(request) @@ -160,7 +160,7 @@ def request(self, repository, token): 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), } request = self.factory.get( - '/api/repository/{}/{}/'.format( + '/v1/repository/{}/{}/'.format( repository.owner.nickname, repository.slug), **authorization_header) @@ -212,7 +212,7 @@ def test_languages_status(self): 'HTTP_AUTHORIZATION': 'Token {}'.format(self.user_token.key), } request = self.factory.get( - '/api/repository/{}/{}/languagesstatus/'.format( + '/v1/repository/{}/{}/languagesstatus/'.format( self.repository.owner.nickname, self.repository.uuid), **authorization_header) @@ -302,7 +302,7 @@ def request(self, repository, token, data, partial=True): 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), } request = self.factory.patch( - '/api/repository/{}/{}/'.format( + '/v1/repository/{}/{}/'.format( repository.owner.nickname, repository.slug), self.factory._encode_data(data, MULTIPART_CONTENT), @@ -417,7 +417,7 @@ def request(self, repository, token): 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), } request = self.factory.delete( - '/api/repository/{}/{}/'.format( + '/v1/repository/{}/{}/'.format( repository.owner.nickname, repository.slug), **authorization_header) @@ -465,7 +465,7 @@ def setUp(self): def request(self, nickname): request = self.factory.get( - '/api/search-repositories/?nickname={}'.format(nickname) + '/v1/search-repositories/?nickname={}'.format(nickname) ) response = SearchRepositoriesViewSet.as_view( {'get': 'list'} @@ -526,7 +526,7 @@ def setUp(self): def request(self, data={}): request = self.factory.get( - '/api/repositories/', + '/v1/repositories/', data) response = RepositoriesViewSet.as_view({'get': 'list'})(request) response.render() @@ -582,7 +582,7 @@ def request(self, repository, token): 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), } request = self.factory.get( - '/api/repository/{}/{}/train/'.format( + '/v1/repository/{}/{}/train/'.format( repository.owner.nickname, repository.slug), **authorization_header) @@ -622,7 +622,7 @@ def request(self, repository, token, data): 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), } request = self.factory.post( - '/api/repository/{}/{}/analyze/'.format( + '/v1/repository/{}/{}/analyze/'.format( repository.owner.nickname, repository.slug), data, @@ -708,7 +708,7 @@ def request(self, repository, token): 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), } request = self.factory.get( - '/api/repository/{}/{}/languagesstatus/'.format( + '/v1/repository/{}/{}/languagesstatus/'.format( repository.owner.nickname, repository.slug), **authorization_header) diff --git a/bothub/api/v1/tests/test_request.py b/bothub/api/v1/tests/test_request.py index 1cdfe54a..e74c3000 100644 --- a/bothub/api/v1/tests/test_request.py +++ b/bothub/api/v1/tests/test_request.py @@ -34,7 +34,7 @@ def request(self, data, token=None): 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), } if token else {} request = self.factory.post( - '/api/request-authorization/', + '/v1/request-authorization/', data, **authorization_header) response = RequestAuthorizationViewSet.as_view( @@ -97,7 +97,7 @@ def request(self, data, token=None): 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), } if token else {} request = self.factory.get( - '/api/authorization-requests/', + '/v1/authorization-requests/', data, **authorization_header) response = RepositoryAuthorizationRequestsViewSet.as_view( @@ -174,7 +174,7 @@ def request_approve(self, ra, token=None): 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), } if token else {} request = self.factory.put( - '/api/review-authorization-request/{}/'.format(ra.pk), + '/v1/review-authorization-request/{}/'.format(ra.pk), self.factory._encode_data({}, MULTIPART_CONTENT), MULTIPART_CONTENT, **authorization_header) @@ -189,7 +189,7 @@ def request_reject(self, ra, token=None): 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), } if token else {} request = self.factory.delete( - '/api/review-authorization-request/{}/'.format(ra.pk), + '/v1/review-authorization-request/{}/'.format(ra.pk), **authorization_header) response = ReviewAuthorizationRequestViewSet.as_view( {'delete': 'destroy'})(request, pk=ra.pk) diff --git a/bothub/api/v1/tests/test_translate.py b/bothub/api/v1/tests/test_translate.py index 937a2496..bf77f6d5 100644 --- a/bothub/api/v1/tests/test_translate.py +++ b/bothub/api/v1/tests/test_translate.py @@ -38,7 +38,7 @@ def request(self, data, user_token): 'HTTP_AUTHORIZATION': 'Token {}'.format(user_token.key), } request = self.factory.post( - '/api/translate-example/', + '/v1/translate-example/', json.dumps(data), content_type='application/json', **authorization_header) @@ -250,7 +250,7 @@ def request(self, translated, token): 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), } request = self.factory.get( - '/api/translation/{}/'.format(translated.id), + '/v1/translation/{}/'.format(translated.id), **authorization_header) response = RepositoryTranslatedExampleViewSet.as_view( {'get': 'retrieve'})(request, pk=translated.id) @@ -315,7 +315,7 @@ def request(self, translated, token): 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), } request = self.factory.delete( - '/api/translation/{}/'.format(translated.id), + '/v1/translation/{}/'.format(translated.id), **authorization_header) response = RepositoryTranslatedExampleViewSet.as_view( {'delete': 'destroy'})(request, pk=translated.id) @@ -364,7 +364,7 @@ def request(self, data, user_token=None): 'HTTP_AUTHORIZATION': 'Token {}'.format(user_token.key), } if user_token else {} request = self.factory.get( - '/api/translations/', + '/v1/translations/', data, **authorization_header) response = TranslationsViewSet.as_view({'get': 'list'})(request) diff --git a/bothub/api/v1/tests/test_updates.py b/bothub/api/v1/tests/test_updates.py index e1162085..baebd47f 100644 --- a/bothub/api/v1/tests/test_updates.py +++ b/bothub/api/v1/tests/test_updates.py @@ -38,7 +38,7 @@ def request(self, data, token=None): 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), } if token else {} request = self.factory.get( - '/api/updates/', + '/v1/updates/', data, **authorization_header) response = RepositoryUpdatesViewSet.as_view( diff --git a/bothub/api/v1/tests/test_user.py b/bothub/api/v1/tests/test_user.py index 50545b4a..11a656b8 100644 --- a/bothub/api/v1/tests/test_user.py +++ b/bothub/api/v1/tests/test_user.py @@ -23,7 +23,7 @@ def setUp(self): def request(self, data): request = self.factory.post( - '/api/register/', + '/v1/register/', data) response = RegisterUserViewSet.as_view( {'post': 'create'})(request) @@ -109,7 +109,7 @@ def request(self, user, data, token): 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), } request = self.factory.patch( - '/api/my-profile/', + '/v1/my-profile/', self.factory._encode_data(data, MULTIPART_CONTENT), MULTIPART_CONTENT, **authorization_header) @@ -151,7 +151,7 @@ def setUp(self): def request(self, data): request = self.factory.post( - '/api/login/', + '/v1/login/', data) response = LoginViewSet.as_view( {'post': 'create'})(request) @@ -194,7 +194,7 @@ def request(self, data, token): 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), } request = self.factory.post( - '/api/', + '/v1/', data, **authorization_header) response = ChangePasswordViewSet.as_view( @@ -243,7 +243,7 @@ def setUp(self): def request(self, data): request = self.factory.post( - '/api/forgot-password/', + '/v1/forgot-password/', data) response = RequestResetPassword.as_view( {'post': 'create'})(request) @@ -280,7 +280,7 @@ def setUp(self): def request(self, nickname, data): request = self.factory.post( - '/api/reset-password/{}/'.format(nickname), + '/v1/reset-password/{}/'.format(nickname), data) response = ResetPassword.as_view( {'post': 'update'})(request, nickname=nickname) @@ -327,7 +327,7 @@ def request(self, token): 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), } request = self.factory.get( - '/api/my-profile/', + '/v1/my-profile/', **authorization_header) response = MyUserProfileViewSet.as_view( {'get': 'retrieve'})(request) diff --git a/bothub/api/v2/tests/test_evaluate.py b/bothub/api/v2/tests/test_evaluate.py index 41442f4e..771af98e 100644 --- a/bothub/api/v2/tests/test_evaluate.py +++ b/bothub/api/v2/tests/test_evaluate.py @@ -54,7 +54,7 @@ def request(self, token): 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), } request = self.factory.get( - '/api/v2/evaluate/?repository_uuid={}'.format( + '/v2/evaluate/?repository_uuid={}'.format( self.repository.uuid ), **authorization_header ) @@ -107,7 +107,7 @@ def request(self, data, token): 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), } request = self.factory.post( - '/api/v2/evaluate/?repository_uuid={}'.format( + '/v2/evaluate/?repository_uuid={}'.format( self.repository.uuid ), json.dumps(data), @@ -218,7 +218,7 @@ def request(self, token): 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), } request = self.factory.delete( - '/api/v2/evaluate/{}/?repository_uuid={}'.format( + '/v2/evaluate/{}/?repository_uuid={}'.format( self.repository_evaluate.id, self.repository.uuid ), **authorization_header @@ -293,7 +293,7 @@ def request(self, data, token): 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), } request = self.factory.patch( - '/api/v2/evaluate/{}/?repository_uuid={}'.format( + '/v2/evaluate/{}/?repository_uuid={}'.format( self.repository_evaluate.id, self.repository.uuid ), @@ -501,7 +501,7 @@ def request(self, token): 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), } request = self.factory.get( - '/api/v2/evaluate/results/?repository_uuid={}'.format( + '/v2/evaluate/results/?repository_uuid={}'.format( self.repository.uuid ), **authorization_header ) @@ -680,7 +680,7 @@ def request(self, token, params): 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), } request = self.factory.get( - '/api/v2/evaluate/results/{}/{}'.format( + '/v2/evaluate/results/{}/{}'.format( self.evaluate_result.id, params ), **authorization_header diff --git a/bothub/api/v2/tests/test_examples.py b/bothub/api/v2/tests/test_examples.py index 84b4b758..c7777a50 100644 --- a/bothub/api/v2/tests/test_examples.py +++ b/bothub/api/v2/tests/test_examples.py @@ -74,7 +74,7 @@ def request(self, data={}, token=None): } if token else {} request = self.factory.get( - '/api/v2/examples/', + '/v2/examples/', data, **authorization_header) diff --git a/bothub/api/v2/tests/test_repository.py b/bothub/api/v2/tests/test_repository.py index 19d6cb3f..ec41e234 100644 --- a/bothub/api/v2/tests/test_repository.py +++ b/bothub/api/v2/tests/test_repository.py @@ -116,7 +116,7 @@ def request(self, data, token=None): } if token else {} request = self.factory.post( - '/api/v2/repository/', + '/v2/repository/', data, **authorization_header) @@ -180,7 +180,7 @@ def request(self, repository, token=None): } if token else {} request = self.factory.get( - '/api/v2/repository/{}/'.format(repository.uuid), + '/v2/repository/{}/'.format(repository.uuid), **authorization_header) response = RepositoryViewSet.as_view({'get': 'retrieve'})( @@ -225,7 +225,7 @@ def request(self, repository, data={}, token=None): } if token else {} request = self.factory.patch( - '/api/v2/repository/{}/'.format(repository.uuid), + '/v2/repository/{}/'.format(repository.uuid), self.factory._encode_data(data, MULTIPART_CONTENT), MULTIPART_CONTENT, **authorization_header) @@ -284,7 +284,7 @@ def request(self, repository, token=None): } if token else {} request = self.factory.get( - '/api/v2/repository/{}/'.format(repository.uuid), + '/v2/repository/{}/'.format(repository.uuid), **authorization_header) response = RepositoryViewSet.as_view({'get': 'retrieve'})( @@ -333,7 +333,7 @@ def request(self, repository, token=None): } if token else {} request = self.factory.get( - '/api/v2/repository/{}/'.format(repository.uuid), + '/v2/repository/{}/'.format(repository.uuid), **authorization_header) response = RepositoryViewSet.as_view({'get': 'retrieve'})( @@ -427,7 +427,7 @@ def request(self, data={}, token=None): 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), } if token else {} request = self.factory.get( - '/api/v2/repositories/', + '/v2/repositories/', data, **authorization_header, ) @@ -507,7 +507,7 @@ def request(self, data={}, token=None): 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), } if token else {} request = self.factory.get( - '/api/v2/repositories/', + '/v2/repositories/', data, **authorization_header, ) @@ -630,7 +630,7 @@ def request(self, param, value, token): 'HTTP_AUTHORIZATION': 'Token {}'.format(token), } request = self.factory.get( - '/api/v2/repository-votes/?{}={}'.format( + '/v2/repository-votes/?{}={}'.format( param, value ), **authorization_header @@ -709,7 +709,7 @@ def request(self, data, token): 'HTTP_AUTHORIZATION': 'Token {}'.format(token), } request = self.factory.post( - '/api/v2/repository-votes/', + '/v2/repository-votes/', json.dumps(data), content_type='application/json', **authorization_header @@ -773,7 +773,7 @@ def request(self, token): 'HTTP_AUTHORIZATION': 'Token {}'.format(token), } request = self.factory.delete( - '/api/v2/repository-votes/{}/'.format(str(self.repository.uuid)), + '/v2/repository-votes/{}/'.format(str(self.repository.uuid)), **authorization_header ) response = RepositoryVotesViewSet.as_view({'delete': 'destroy'})( @@ -830,7 +830,7 @@ def setUp(self): def request(self): request = self.factory.get( - '/api/v2/repositories-contributions/?nickname={}'.format( + '/v2/repositories-contributions/?nickname={}'.format( self.user.nickname ) ) From b375bd93a6e0dfcd836206b4062fdd2a8988b3d4 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Tue, 23 Jul 2019 14:21:27 -0300 Subject: [PATCH 085/207] PEP8 --- bothub/urls.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/bothub/urls.py b/bothub/urls.py index 9351c747..dad61274 100644 --- a/bothub/urls.py +++ b/bothub/urls.py @@ -1,7 +1,6 @@ from django.contrib import admin -from django.urls import path, include, re_path +from django.urls import path, include from django.conf import settings -from rest_framework.documentation import include_docs_urls from rest_framework import permissions from drf_yasg.views import get_schema_view From 9bb65896c82a32d95641de1500591bc00955fe74 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Fri, 2 Aug 2019 14:37:05 -0300 Subject: [PATCH 086/207] Deploy Heroku --- Pipfile | 4 + Pipfile.lock | 249 ++++++++++++++++++++++++++++++++++----------- Procfile | 1 + app.json | 22 ++++ bothub/settings.py | 4 + runtime.txt | 1 + 6 files changed, 219 insertions(+), 62 deletions(-) create mode 100644 Procfile create mode 100644 app.json create mode 100644 runtime.txt diff --git a/Pipfile b/Pipfile index 4ef22d6f..26e6d722 100644 --- a/Pipfile +++ b/Pipfile @@ -15,6 +15,10 @@ coreapi = "==2.3.3" whitenoise = "==4.1.2" pytz = "==2018.7" drf-yasg = "*" +django-heroku = "*" +gunicorn = "*" +gevent = "*" +packaging = "*" [dev-packages] "flake8" = "*" diff --git a/Pipfile.lock b/Pipfile.lock index a6675b6f..a5e7a270 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "648422adf916fcfeff0b93f66fb660e85da82a5fcf4944bc8d53b7cdf4eb5b82" + "sha256": "6d0c222284c1b28685de66e03cc04014a56450aaca47dba3d0dfd74cd4358b55" }, "pipfile-spec": 6, "requires": { @@ -16,6 +16,13 @@ ] }, "default": { + "attrs": { + "hashes": [ + "sha256:69c0dbf2ed392de1cb5ec704444b08a5ef81680a61cb899dc08127123af36a79", + "sha256:f0b870f674851ecbfbbbd364d6b5cbdff9dcedbc7f3f5e18a6891057f21fe399" + ], + "version": "==19.1.0" + }, "certifi": { "hashes": [ "sha256:046832c04d4e752f37383b628bc601a7ea7211496b4638f6514d0e5b9acc4939", @@ -77,6 +84,14 @@ "index": "pypi", "version": "==2.0.0" }, + "django-heroku": { + "hashes": [ + "sha256:2bc690aab89eedbe01311752320a9a12e7548e3b0ed102681acc5736a41a4762", + "sha256:6af4bc3ae4a9b55eaad6dbe5164918982d2762661aebc9f83d9fa49f6009514e" + ], + "index": "pypi", + "version": "==0.3.1" + }, "djangorestframework": { "hashes": [ "sha256:607865b0bb1598b153793892101d881466bd5a991de12bd6229abb18b1c86136", @@ -93,6 +108,68 @@ "index": "pypi", "version": "==1.16.1" }, + "gevent": { + "hashes": [ + "sha256:0774babec518a24d9a7231d4e689931f31b332c4517a771e532002614e270a64", + "sha256:0e1e5b73a445fe82d40907322e1e0eec6a6745ca3cea19291c6f9f50117bb7ea", + "sha256:0ff2b70e8e338cf13bedf146b8c29d475e2a544b5d1fe14045aee827c073842c", + "sha256:107f4232db2172f7e8429ed7779c10f2ed16616d75ffbe77e0e0c3fcdeb51a51", + "sha256:14b4d06d19d39a440e72253f77067d27209c67e7611e352f79fe69e0f618f76e", + "sha256:1b7d3a285978b27b469c0ff5fb5a72bcd69f4306dbbf22d7997d83209a8ba917", + "sha256:1eb7fa3b9bd9174dfe9c3b59b7a09b768ecd496debfc4976a9530a3e15c990d1", + "sha256:2711e69788ddb34c059a30186e05c55a6b611cb9e34ac343e69cf3264d42fe1c", + "sha256:28a0c5417b464562ab9842dd1fb0cc1524e60494641d973206ec24d6ec5f6909", + "sha256:3249011d13d0c63bea72d91cec23a9cf18c25f91d1f115121e5c9113d753fa12", + "sha256:44089ed06a962a3a70e96353c981d628b2d4a2f2a75ea5d90f916a62d22af2e8", + "sha256:4bfa291e3c931ff3c99a349d8857605dca029de61d74c6bb82bd46373959c942", + "sha256:50024a1ee2cf04645535c5ebaeaa0a60c5ef32e262da981f4be0546b26791950", + "sha256:53b72385857e04e7faca13c613c07cab411480822ac658d97fd8a4ddbaf715c8", + "sha256:74b7528f901f39c39cdbb50cdf08f1a2351725d9aebaef212a29abfbb06895ee", + "sha256:7d0809e2991c9784eceeadef01c27ee6a33ca09ebba6154317a257353e3af922", + "sha256:896b2b80931d6b13b5d9feba3d4eebc67d5e6ec54f0cf3339d08487d55d93b0e", + "sha256:8d9ec51cc06580f8c21b41fd3f2b3465197ba5b23c00eb7d422b7ae0380510b0", + "sha256:9f7a1e96fec45f70ad364e46de32ccacab4d80de238bd3c2edd036867ccd48ad", + "sha256:ab4dc33ef0e26dc627559786a4fba0c2227f125db85d970abbf85b77506b3f51", + "sha256:d1e6d1f156e999edab069d79d890859806b555ce4e4da5b6418616322f0a3df1", + "sha256:d752bcf1b98174780e2317ada12013d612f05116456133a6acf3e17d43b71f05", + "sha256:e5bcc4270671936349249d26140c267397b7b4b1381f5ec8b13c53c5b53ab6e1" + ], + "index": "pypi", + "version": "==1.4.0" + }, + "greenlet": { + "hashes": [ + "sha256:000546ad01e6389e98626c1367be58efa613fa82a1be98b0c6fc24b563acc6d0", + "sha256:0d48200bc50cbf498716712129eef819b1729339e34c3ae71656964dac907c28", + "sha256:23d12eacffa9d0f290c0fe0c4e81ba6d5f3a5b7ac3c30a5eaf0126bf4deda5c8", + "sha256:37c9ba82bd82eb6a23c2e5acc03055c0e45697253b2393c9a50cef76a3985304", + "sha256:51503524dd6f152ab4ad1fbd168fc6c30b5795e8c70be4410a64940b3abb55c0", + "sha256:8041e2de00e745c0e05a502d6e6db310db7faa7c979b3a5877123548a4c0b214", + "sha256:81fcd96a275209ef117e9ec91f75c731fa18dcfd9ffaa1c0adbdaa3616a86043", + "sha256:853da4f9563d982e4121fed8c92eea1a4594a2299037b3034c3c898cb8e933d6", + "sha256:8b4572c334593d449113f9dc8d19b93b7b271bdbe90ba7509eb178923327b625", + "sha256:9416443e219356e3c31f1f918a91badf2e37acf297e2fa13d24d1cc2380f8fbc", + "sha256:9854f612e1b59ec66804931df5add3b2d5ef0067748ea29dc60f0efdcda9a638", + "sha256:99a26afdb82ea83a265137a398f570402aa1f2b5dfb4ac3300c026931817b163", + "sha256:a19bf883b3384957e4a4a13e6bd1ae3d85ae87f4beb5957e35b0be287f12f4e4", + "sha256:a9f145660588187ff835c55a7d2ddf6abfc570c2651c276d3d4be8a2766db490", + "sha256:ac57fcdcfb0b73bb3203b58a14501abb7e5ff9ea5e2edfa06bb03035f0cff248", + "sha256:bcb530089ff24f6458a81ac3fa699e8c00194208a724b644ecc68422e1111939", + "sha256:beeabe25c3b704f7d56b573f7d2ff88fc99f0138e43480cecdfcaa3b87fe4f87", + "sha256:d634a7ea1fc3380ff96f9e44d8d22f38418c1c381d5fac680b272d7d90883720", + "sha256:d97b0661e1aead761f0ded3b769044bb00ed5d33e1ec865e891a8b128bf7c656" + ], + "markers": "platform_python_implementation == 'CPython'", + "version": "==0.4.15" + }, + "gunicorn": { + "hashes": [ + "sha256:aa8e0b40b4157b36a5df5e599f45c9c76d6af43845ba3b3b0efe2c70473c2471", + "sha256:fa2662097c66f920f53f70621c6c58ca4a3c4d3434205e608e121b5b3b71f4f3" + ], + "index": "pypi", + "version": "==19.9.0" + }, "idna": { "hashes": [ "sha256:156a6814fb5ac1fc6850fb002e0852d56c0c8d2531923a51032d1b70760e186e", @@ -152,6 +229,37 @@ ], "version": "==1.1.1" }, + "packaging": { + "hashes": [ + "sha256:a7ac867b97fdc07ee80a8058fe4435ccd274ecc3b0ed61d852d7d53055528cf9", + "sha256:c491ca87294da7cc01902edbe30a5bc6c4c28172b5138ab4e4aa1b9d7bfaeafe" + ], + "index": "pypi", + "version": "==19.1" + }, + "psycopg2": { + "hashes": [ + "sha256:128d0fa910ada0157bba1cb74a9c5f92bb8a1dca77cf91a31eb274d1f889e001", + "sha256:227fd46cf9b7255f07687e5bde454d7d67ae39ca77e170097cdef8ebfc30c323", + "sha256:2315e7f104681d498ccf6fd70b0dba5bce65d60ac92171492bfe228e21dcc242", + "sha256:4b5417dcd2999db0f5a891d54717cfaee33acc64f4772c4bc574d4ff95ed9d80", + "sha256:640113ddc943522aaf71294e3f2d24013b0edd659b7820621492c9ebd3a2fb0b", + "sha256:897a6e838319b4bf648a574afb6cabcb17d0488f8c7195100d48d872419f4457", + "sha256:8dceca81409898c870e011c71179454962dec152a1a6b86a347f4be74b16d864", + "sha256:b1b8e41da09a0c3ef0b3d4bb72da0dde2abebe583c1e8462973233fd5ad0235f", + "sha256:cb407fccc12fc29dc331f2b934913405fa49b9b75af4f3a72d0f50f57ad2ca23", + "sha256:d3a27550a8185e53b244ad7e79e307594b92fede8617d80200a8cce1fba2c60f", + "sha256:f0e6b697a975d9d3ccd04135316c947dd82d841067c7800ccf622a8717e98df1" + ], + "version": "==2.8.3" + }, + "pyparsing": { + "hashes": [ + "sha256:6f98a7b9397e206d78cc01df10131398f1c8b8510a2f4d97d9abd82e1aacdd80", + "sha256:d9338df12903bbf5d65a0e4e87c2161968b10d2e489652bb47001d82a9b028b4" + ], + "version": "==2.4.2" + }, "python-decouple": { "hashes": [ "sha256:1317df14b43efee4337a4aa02914bf004f010cd56d6c4bd894e6474ec8c4fe2d" @@ -177,26 +285,35 @@ }, "ruamel.yaml": { "hashes": [ - "sha256:08aaaa74ff66565024ecabf9ba2db212712382a21c0458f9a91c623a1fa83b34", - "sha256:23f2efb872d2ebe3d5428b4f1a8f30cbf59f56e780c4981c155411ee65572673", - "sha256:38718e69270141c403b5fc539f774ed394568f8a5195b507991f5b690356facb", - "sha256:44da2be1153e173f90ad8775d4ac4237a3c06cfbb9660c1c1980271621833faa", - "sha256:4b1674a936cdae9735578d4fd64bcbc6cfbb77a1a8f7037a50c6e3874ba4c9d8", - "sha256:51d49c870aca850e652e2cd1c9bea9b52b77d13ad52b0556de496c1d264ea65f", - "sha256:63dc8c6147a4cf77efadf2ae0f34e89e03de79289298bb941b7ae333d5d4020b", - "sha256:6672798c6b52a976a7b24e20665055852388c83198d88029d3c76e2197ac221a", - "sha256:6b6025f9b6a557e15e9fdfda4d9af0b57cd8d59ff98e23a0097ab2d7c0540f07", - "sha256:7b750252e3d1ec5b53d03be508796c04a907060900c7d207280b7456650ebbfc", - "sha256:847177699994f9c31adf78d1ef1ff8f069ef0241e744a3ee8b30fbdaa914cc1e", - "sha256:8e42f3067a59e819935a2926e247170ed93c8f0b2ab64526f888e026854db2e4", - "sha256:922d9e483c05d9000256640026f277fcc0c2e1e9271d05acada8e6cfb4c8b721", - "sha256:92a8ca79f9173cca29ca9663b49d9c936aefc4c8a76f39318b0218c8f3626438", - "sha256:ab8eeca4de4decf0d0a42cb6949d354da9fc70a2d9201f0dd55186c599b2e3a5", - "sha256:bd4b60b649f4a81086f70cd56eff4722018ef36a28094c396f1a53bf450bd579", - "sha256:fc6471ef15b69e454cca82433ac5f84929d9f3e2d72b9e54b06850b6b7133cc0", - "sha256:ffc89770339191acbe5a15041950b5ad9daec7d659619b0ed9dad8c9c80c26f3" - ], - "version": "==0.15.100" + "sha256:4c1dbad22790b5ea8587c2a0cae97ebc7a9d0d88de5d0edb70dea2eab7d8534a", + "sha256:eb4b1ffd095785c50f110118cb6f7bb9cd011ecc013b014436d38b7f8fb7afa9" + ], + "version": "==0.16.0" + }, + "ruamel.yaml.clib": { + "hashes": [ + "sha256:32c37bdc7ee5fbc5e794b497b98f98ecc12e1f1541cdd3bbd65f8ec32e0270d2", + "sha256:385b70734435d2f66f00823d4e224c1a4b53dfeaf9ded3a655a6a2f9c229b1f6", + "sha256:4040ddea350698138e341395508b8dd7610b2312177cb41c8db2b6260adee348", + "sha256:4dc088e55e0cc3f8c18652e830e3ecff159425f01327de4d94e5ce473fdcd2f8", + "sha256:53768934bc28ce07ca82c02d9db6717ae9bad4cdf9511d3a3e6d1b576235d04e", + "sha256:53fd2ef53be8301707662f4c353731d97a4cb2b372972b7dcd73ef245dbab9e9", + "sha256:5712728e6ba56d3b93f5f99a175760c778420caae714687592548c4f7699782e", + "sha256:66df3233e5cca3528be2a700f2a54e26262dde6d5e22b34953e7f44785857c8c", + "sha256:750a15f07178d91204ce4baffb16697cef4c8f583495d4f0fec52902dad8e7fc", + "sha256:820ec13201ed5c015dc74ea7087b2c5c56b8aeb51af4b7d7c859e0b45c07f035", + "sha256:8dcab8a09c17a030d046749eb97ed9a81e02bb642d7816e8757fc5a3016af89d", + "sha256:9e1acd628f2bf601fd4df69523476ee4640be8ba7d9aff8f04cd66a1ae07f119", + "sha256:b31bc078c9bac3dbb5855e94eb382aeef23076bf3d1a2d02ee8d91c55567cb08", + "sha256:b7a681e2d6dbd147ec9808cb1a736c1ef96bc2c693f54e0fc01fe0d10409bd88", + "sha256:c1333e8911c29c6e209db117345141d5fcb772464d62cac3e117912a965d9619", + "sha256:d583e7b9646418dff5ee0e36875b3cabc3d0fb925dfdeec239697c583388f9b2", + "sha256:da610ff9feeb075641128ce40881d2ac3c8e57e7ea04636169b0c3b5e8f711f7", + "sha256:e9b6ebb62806817b01e9eea9fc7da57c12557e44e94e79f5fa82eca4bc7fad60", + "sha256:f36035f1c0b6a7a20010e98b582d38272514a77f34cd45ec0d2847abaa89ac78" + ], + "markers": "platform_python_implementation == 'CPython' and python_version < '3.8'", + "version": "==0.1.0" }, "six": { "hashes": [ @@ -238,6 +355,13 @@ "markers": "sys_platform == 'darwin'", "version": "==0.1.0" }, + "attrs": { + "hashes": [ + "sha256:69c0dbf2ed392de1cb5ec704444b08a5ef81680a61cb899dc08127123af36a79", + "sha256:f0b870f674851ecbfbbbd364d6b5cbdff9dcedbc7f3f5e18a6891057f21fe399" + ], + "version": "==19.1.0" + }, "autopep8": { "hashes": [ "sha256:4d8eec30cc81bc5617dbf1218201d770dc35629363547f17577c61683ccfb3ee" @@ -254,40 +378,41 @@ }, "coverage": { "hashes": [ - "sha256:3684fabf6b87a369017756b551cef29e505cb155ddb892a7a29277b978da88b9", - "sha256:39e088da9b284f1bd17c750ac672103779f7954ce6125fd4382134ac8d152d74", - "sha256:3c205bc11cc4fcc57b761c2da73b9b72a59f8d5ca89979afb0c1c6f9e53c7390", - "sha256:465ce53a8c0f3a7950dfb836438442f833cf6663d407f37d8c52fe7b6e56d7e8", - "sha256:48020e343fc40f72a442c8a1334284620f81295256a6b6ca6d8aa1350c763bbe", - "sha256:5296fc86ab612ec12394565c500b412a43b328b3907c0d14358950d06fd83baf", - "sha256:5f61bed2f7d9b6a9ab935150a6b23d7f84b8055524e7be7715b6513f3328138e", - "sha256:68a43a9f9f83693ce0414d17e019daee7ab3f7113a70c79a3dd4c2f704e4d741", - "sha256:6b8033d47fe22506856fe450470ccb1d8ba1ffb8463494a15cfc96392a288c09", - "sha256:7ad7536066b28863e5835e8cfeaa794b7fe352d99a8cded9f43d1161be8e9fbd", - "sha256:7bacb89ccf4bedb30b277e96e4cc68cd1369ca6841bde7b005191b54d3dd1034", - "sha256:839dc7c36501254e14331bcb98b27002aa415e4af7ea039d9009409b9d2d5420", - "sha256:8f9a95b66969cdea53ec992ecea5406c5bd99c9221f539bca1e8406b200ae98c", - "sha256:932c03d2d565f75961ba1d3cec41ddde00e162c5b46d03f7423edcb807734eab", - "sha256:988529edadc49039d205e0aa6ce049c5ccda4acb2d6c3c5c550c17e8c02c05ba", - "sha256:998d7e73548fe395eeb294495a04d38942edb66d1fa61eb70418871bc621227e", - "sha256:9de60893fb447d1e797f6bf08fdf0dbcda0c1e34c1b06c92bd3a363c0ea8c609", - "sha256:9e80d45d0c7fcee54e22771db7f1b0b126fb4a6c0a2e5afa72f66827207ff2f2", - "sha256:a545a3dfe5082dc8e8c3eb7f8a2cf4f2870902ff1860bd99b6198cfd1f9d1f49", - "sha256:a5d8f29e5ec661143621a8f4de51adfb300d7a476224156a39a392254f70687b", - "sha256:aca06bfba4759bbdb09bf52ebb15ae20268ee1f6747417837926fae990ebc41d", - "sha256:bb23b7a6fd666e551a3094ab896a57809e010059540ad20acbeec03a154224ce", - "sha256:bfd1d0ae7e292105f29d7deaa9d8f2916ed8553ab9d5f39ec65bcf5deadff3f9", - "sha256:c62ca0a38958f541a73cf86acdab020c2091631c137bd359c4f5bddde7b75fd4", - "sha256:c709d8bda72cf4cd348ccec2a4881f2c5848fd72903c185f363d361b2737f773", - "sha256:c968a6aa7e0b56ecbd28531ddf439c2ec103610d3e2bf3b75b813304f8cb7723", - "sha256:df785d8cb80539d0b55fd47183264b7002077859028dfe3070cf6359bf8b2d9c", - "sha256:f406628ca51e0ae90ae76ea8398677a921b36f0bd71aab2099dfed08abd0322f", - "sha256:f46087bbd95ebae244a0eda01a618aff11ec7a069b15a3ef8f6b520db523dcf1", - "sha256:f8019c5279eb32360ca03e9fac40a12667715546eed5c5eb59eb381f2f501260", - "sha256:fc5f4d209733750afd2714e9109816a29500718b32dd9a5db01c0cb3a019b96a" + "sha256:08907593569fe59baca0bf152c43f3863201efb6113ecb38ce7e97ce339805a6", + "sha256:0be0f1ed45fc0c185cfd4ecc19a1d6532d72f86a2bac9de7e24541febad72650", + "sha256:141f08ed3c4b1847015e2cd62ec06d35e67a3ac185c26f7635f4406b90afa9c5", + "sha256:19e4df788a0581238e9390c85a7a09af39c7b539b29f25c89209e6c3e371270d", + "sha256:23cc09ed395b03424d1ae30dcc292615c1372bfba7141eb85e11e50efaa6b351", + "sha256:245388cda02af78276b479f299bbf3783ef0a6a6273037d7c60dc73b8d8d7755", + "sha256:331cb5115673a20fb131dadd22f5bcaf7677ef758741312bee4937d71a14b2ef", + "sha256:386e2e4090f0bc5df274e720105c342263423e77ee8826002dcffe0c9533dbca", + "sha256:3a794ce50daee01c74a494919d5ebdc23d58873747fa0e288318728533a3e1ca", + "sha256:60851187677b24c6085248f0a0b9b98d49cba7ecc7ec60ba6b9d2e5574ac1ee9", + "sha256:63a9a5fc43b58735f65ed63d2cf43508f462dc49857da70b8980ad78d41d52fc", + "sha256:6b62544bb68106e3f00b21c8930e83e584fdca005d4fffd29bb39fb3ffa03cb5", + "sha256:6ba744056423ef8d450cf627289166da65903885272055fb4b5e113137cfa14f", + "sha256:7494b0b0274c5072bddbfd5b4a6c6f18fbbe1ab1d22a41e99cd2d00c8f96ecfe", + "sha256:826f32b9547c8091679ff292a82aca9c7b9650f9fda3e2ca6bf2ac905b7ce888", + "sha256:93715dffbcd0678057f947f496484e906bf9509f5c1c38fc9ba3922893cda5f5", + "sha256:9a334d6c83dfeadae576b4d633a71620d40d1c379129d587faa42ee3e2a85cce", + "sha256:af7ed8a8aa6957aac47b4268631fa1df984643f07ef00acd374e456364b373f5", + "sha256:bf0a7aed7f5521c7ca67febd57db473af4762b9622254291fbcbb8cd0ba5e33e", + "sha256:bf1ef9eb901113a9805287e090452c05547578eaab1b62e4ad456fcc049a9b7e", + "sha256:c0afd27bc0e307a1ffc04ca5ec010a290e49e3afbe841c5cafc5c5a80ecd81c9", + "sha256:dd579709a87092c6dbee09d1b7cfa81831040705ffa12a1b248935274aee0437", + "sha256:df6712284b2e44a065097846488f66840445eb987eb81b3cc6e4149e7b6982e1", + "sha256:e07d9f1a23e9e93ab5c62902833bf3e4b1f65502927379148b6622686223125c", + "sha256:e2ede7c1d45e65e209d6093b762e98e8318ddeff95317d07a27a2140b80cfd24", + "sha256:e4ef9c164eb55123c62411f5936b5c2e521b12356037b6e1c2617cef45523d47", + "sha256:eca2b7343524e7ba246cab8ff00cab47a2d6d54ada3b02772e908a45675722e2", + "sha256:eee64c616adeff7db37cc37da4180a3a5b6177f5c46b187894e633f088fb5b28", + "sha256:ef824cad1f980d27f26166f86856efe11eff9912c4fed97d3804820d43fa550c", + "sha256:efc89291bd5a08855829a3c522df16d856455297cf35ae827a37edac45f466a7", + "sha256:fa964bae817babece5aa2e8c1af841bebb6d0b9add8e637548809d040443fee0", + "sha256:ff37757e068ae606659c28c3bd0d923f9d29a85de79bf25b2b34b148473b5025" ], "index": "pypi", - "version": "==4.5.3" + "version": "==4.5.4" }, "decorator": { "hashes": [ @@ -313,11 +438,11 @@ }, "ipython": { "hashes": [ - "sha256:11067ab11d98b1e6c7f0993506f7a5f8a91af420f7e82be6575fcb7a6ca372a0", - "sha256:60bc55c2c1d287161191cc2469e73c116d9b634cff25fe214a43cba7cec94c79" + "sha256:1d3a1692921e932751bc1a1f7bb96dc38671eeefdc66ed33ee4cbc57e92a410e", + "sha256:537cd0176ff6abd06ef3e23f2d0c4c2c8a4d9277b7451544c6cbf56d1c79a83d" ], "index": "pypi", - "version": "==7.6.1" + "version": "==7.7.0" }, "ipython-genutils": { "hashes": [ @@ -342,11 +467,11 @@ }, "packaging": { "hashes": [ - "sha256:0c98a5d0be38ed775798ece1b9727178c4469d9c3b4ada66e8e6b7849f8732af", - "sha256:9e1cbf8c12b1f1ce0bb5344b8d7ecf66a6f8a6e91bcb0c84593ed6d3ab5c4ab3" + "sha256:a7ac867b97fdc07ee80a8058fe4435ccd274ecc3b0ed61d852d7d53055528cf9", + "sha256:c491ca87294da7cc01902edbe30a5bc6c4c28172b5138ab4e4aa1b9d7bfaeafe" ], "index": "pypi", - "version": "==19.0" + "version": "==19.1" }, "parso": { "hashes": [ @@ -408,10 +533,10 @@ }, "pyparsing": { "hashes": [ - "sha256:530d8bf8cc93a34019d08142593cf4d78a05c890da8cf87ffa3120af53772238", - "sha256:f78e99616b6f1a4745c0580e170251ef1bbafc0d0513e270c4bd281bf29d2800" + "sha256:6f98a7b9397e206d78cc01df10131398f1c8b8510a2f4d97d9abd82e1aacdd80", + "sha256:d9338df12903bbf5d65a0e4e87c2161968b10d2e489652bb47001d82a9b028b4" ], - "version": "==2.4.1" + "version": "==2.4.2" }, "six": { "hashes": [ diff --git a/Procfile b/Procfile new file mode 100644 index 00000000..2631d89d --- /dev/null +++ b/Procfile @@ -0,0 +1 @@ +web: python manage.py migrate && python manage.py fill_db_using_fake_data && gunicorn bothub.wsgi -b 0.0.0.0:\$PORT --log-file - diff --git a/app.json b/app.json new file mode 100644 index 00000000..dbfdb66e --- /dev/null +++ b/app.json @@ -0,0 +1,22 @@ +{ + "name": "Bothub Engine", + "image": "heroku/python", + "repository": "https://github.com/Ilhasoft/bothub-engine/", + "logo": "https://avatars0.githubusercontent.com/u/8379703?s=200&v=4", + "keywords": ["bothub", "ia", "django", "python"], + "website": "https://bothub.it", + "addons": [ "heroku-postgresql" ], + "env": { + "DISABLE_COLLECTSTATIC": "1", + "SECRET_KEY": "SK", + "DEBUG": "1" + }, + "environments": { + "test": { + "scripts": { + "test-setup": "python manage.py collectstatic --noinput", + "test": "python manage.py test" + } + } + } +} \ No newline at end of file diff --git a/bothub/settings.py b/bothub/settings.py index 9d006705..c6d6f253 100644 --- a/bothub/settings.py +++ b/bothub/settings.py @@ -1,5 +1,6 @@ import os import dj_database_url +import django_heroku from decouple import config from django.utils.log import DEFAULT_LOGGING @@ -261,3 +262,6 @@ }, }, } + +# Configure Django App for Heroku. +django_heroku.settings(locals()) diff --git a/runtime.txt b/runtime.txt new file mode 100644 index 00000000..82347234 --- /dev/null +++ b/runtime.txt @@ -0,0 +1 @@ +python-3.6.8 \ No newline at end of file From 0930671ec7d513376182a2c85d1c71ec34379b0f Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Fri, 2 Aug 2019 14:44:09 -0300 Subject: [PATCH 087/207] Added Heroku README --- README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/README.md b/README.md index a7946dc1..154b3837 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,17 @@ Run ```pipenv run python ./manage.py fill_db_using_fake_data``` to fill database Docker images available in [Bothub's Docker Hub repository](https://hub.docker.com/r/ilha/bothub/). + +# Deployment + + +## Heroku +Host your own Bothub Engine ** FREE ** with [One-Click Deploy] (https://heroku.com/deploy). + +[![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy?template=https://github.com/Ilhasoft/bothub-engine/tree/master) + + + ## Environment Variables You can set environment variables in your OS, write on ```.env``` file or pass via Docker config. From 6b345b2607af2183223fd40d628a51614bb0b0ae Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Fri, 2 Aug 2019 14:46:11 -0300 Subject: [PATCH 088/207] Update README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 154b3837..38367b62 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ Docker images available in [Bothub's Docker Hub repository](https://hub.docker.c ## Heroku -Host your own Bothub Engine ** FREE ** with [One-Click Deploy] (https://heroku.com/deploy). +Host your own Bothub Engine with [One-Click Deploy] (https://heroku.com/deploy). [![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy?template=https://github.com/Ilhasoft/bothub-engine/tree/master) From 144b53e7803a2f734310a9935dd2431bcd8c910a Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Fri, 2 Aug 2019 14:47:16 -0300 Subject: [PATCH 089/207] Update README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 38367b62..802923c2 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ Docker images available in [Bothub's Docker Hub repository](https://hub.docker.c ## Heroku Host your own Bothub Engine with [One-Click Deploy] (https://heroku.com/deploy). -[![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy?template=https://github.com/Ilhasoft/bothub-engine/tree/master) +[![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy) From 4a749ddab35e335b7f00dd4d9caf42471cf70a3d Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Fri, 2 Aug 2019 16:36:37 -0300 Subject: [PATCH 090/207] Update Pipfile --- Pipfile | 1 - Pipfile.lock | 24 +----------------------- 2 files changed, 1 insertion(+), 24 deletions(-) diff --git a/Pipfile b/Pipfile index 26e6d722..60fcb1c9 100644 --- a/Pipfile +++ b/Pipfile @@ -25,7 +25,6 @@ packaging = "*" coverage = "*" ipython = "*" autopep8 = "*" -packaging = "*" [requires] python_version = "3.6" diff --git a/Pipfile.lock b/Pipfile.lock index a5e7a270..e97268bb 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "6d0c222284c1b28685de66e03cc04014a56450aaca47dba3d0dfd74cd4358b55" + "sha256": "617b3ed7326bb528fa6aa89954b98b2c6f54ae589e3a583f8367ac1f2c2c43bb" }, "pipfile-spec": 6, "requires": { @@ -355,13 +355,6 @@ "markers": "sys_platform == 'darwin'", "version": "==0.1.0" }, - "attrs": { - "hashes": [ - "sha256:69c0dbf2ed392de1cb5ec704444b08a5ef81680a61cb899dc08127123af36a79", - "sha256:f0b870f674851ecbfbbbd364d6b5cbdff9dcedbc7f3f5e18a6891057f21fe399" - ], - "version": "==19.1.0" - }, "autopep8": { "hashes": [ "sha256:4d8eec30cc81bc5617dbf1218201d770dc35629363547f17577c61683ccfb3ee" @@ -465,14 +458,6 @@ ], "version": "==0.6.1" }, - "packaging": { - "hashes": [ - "sha256:a7ac867b97fdc07ee80a8058fe4435ccd274ecc3b0ed61d852d7d53055528cf9", - "sha256:c491ca87294da7cc01902edbe30a5bc6c4c28172b5138ab4e4aa1b9d7bfaeafe" - ], - "index": "pypi", - "version": "==19.1" - }, "parso": { "hashes": [ "sha256:63854233e1fadb5da97f2744b6b24346d2750b85965e7e399bec1620232797dc", @@ -531,13 +516,6 @@ ], "version": "==2.4.2" }, - "pyparsing": { - "hashes": [ - "sha256:6f98a7b9397e206d78cc01df10131398f1c8b8510a2f4d97d9abd82e1aacdd80", - "sha256:d9338df12903bbf5d65a0e4e87c2161968b10d2e489652bb47001d82a9b028b4" - ], - "version": "==2.4.2" - }, "six": { "hashes": [ "sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c", From 6b6bf00cd470dad5e3da17788f3fcc9e6cf0fdb5 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Fri, 2 Aug 2019 16:40:40 -0300 Subject: [PATCH 091/207] Test Heroku Settings --- bothub/settings.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/bothub/settings.py b/bothub/settings.py index c6d6f253..9d006705 100644 --- a/bothub/settings.py +++ b/bothub/settings.py @@ -1,6 +1,5 @@ import os import dj_database_url -import django_heroku from decouple import config from django.utils.log import DEFAULT_LOGGING @@ -262,6 +261,3 @@ }, }, } - -# Configure Django App for Heroku. -django_heroku.settings(locals()) From a0a39841279206d7ce7b5f8e8348624a7eba5555 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Fri, 2 Aug 2019 16:46:54 -0300 Subject: [PATCH 092/207] Update Pipfile Heroku --- Pipfile | 1 - Pipfile.lock | 26 +------------------------- 2 files changed, 1 insertion(+), 26 deletions(-) diff --git a/Pipfile b/Pipfile index 60fcb1c9..3c0f9de8 100644 --- a/Pipfile +++ b/Pipfile @@ -15,7 +15,6 @@ coreapi = "==2.3.3" whitenoise = "==4.1.2" pytz = "==2018.7" drf-yasg = "*" -django-heroku = "*" gunicorn = "*" gevent = "*" packaging = "*" diff --git a/Pipfile.lock b/Pipfile.lock index e97268bb..1491d7dc 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "617b3ed7326bb528fa6aa89954b98b2c6f54ae589e3a583f8367ac1f2c2c43bb" + "sha256": "5f230c8e911d5f0f91321351555b3277e4a6ce71b6fe1843271cefaf6f11559e" }, "pipfile-spec": 6, "requires": { @@ -84,14 +84,6 @@ "index": "pypi", "version": "==2.0.0" }, - "django-heroku": { - "hashes": [ - "sha256:2bc690aab89eedbe01311752320a9a12e7548e3b0ed102681acc5736a41a4762", - "sha256:6af4bc3ae4a9b55eaad6dbe5164918982d2762661aebc9f83d9fa49f6009514e" - ], - "index": "pypi", - "version": "==0.3.1" - }, "djangorestframework": { "hashes": [ "sha256:607865b0bb1598b153793892101d881466bd5a991de12bd6229abb18b1c86136", @@ -237,22 +229,6 @@ "index": "pypi", "version": "==19.1" }, - "psycopg2": { - "hashes": [ - "sha256:128d0fa910ada0157bba1cb74a9c5f92bb8a1dca77cf91a31eb274d1f889e001", - "sha256:227fd46cf9b7255f07687e5bde454d7d67ae39ca77e170097cdef8ebfc30c323", - "sha256:2315e7f104681d498ccf6fd70b0dba5bce65d60ac92171492bfe228e21dcc242", - "sha256:4b5417dcd2999db0f5a891d54717cfaee33acc64f4772c4bc574d4ff95ed9d80", - "sha256:640113ddc943522aaf71294e3f2d24013b0edd659b7820621492c9ebd3a2fb0b", - "sha256:897a6e838319b4bf648a574afb6cabcb17d0488f8c7195100d48d872419f4457", - "sha256:8dceca81409898c870e011c71179454962dec152a1a6b86a347f4be74b16d864", - "sha256:b1b8e41da09a0c3ef0b3d4bb72da0dde2abebe583c1e8462973233fd5ad0235f", - "sha256:cb407fccc12fc29dc331f2b934913405fa49b9b75af4f3a72d0f50f57ad2ca23", - "sha256:d3a27550a8185e53b244ad7e79e307594b92fede8617d80200a8cce1fba2c60f", - "sha256:f0e6b697a975d9d3ccd04135316c947dd82d841067c7800ccf622a8717e98df1" - ], - "version": "==2.8.3" - }, "pyparsing": { "hashes": [ "sha256:6f98a7b9397e206d78cc01df10131398f1c8b8510a2f4d97d9abd82e1aacdd80", From 16dde0549cc4073fcff2f2739e4296431b379807 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Tue, 6 Aug 2019 08:45:48 -0300 Subject: [PATCH 093/207] Change docker-compose --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index 0729943a..18561728 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -23,7 +23,7 @@ services: context: . dockerfile: Dockerfile ports: - - 80:80 + - ${ENGINE_PORT:-80}:80 networks: - default - bothub From 2d3d3af2a15c988fedc8b352ff8abd8f6a4465de Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Wed, 7 Aug 2019 14:44:20 -0300 Subject: [PATCH 094/207] Update Pipfile --- Pipfile | 1 + Pipfile.lock | 150 ++++++++++++++++++++++++++++++--------------------- 2 files changed, 89 insertions(+), 62 deletions(-) diff --git a/Pipfile b/Pipfile index 4ef22d6f..ee318c98 100644 --- a/Pipfile +++ b/Pipfile @@ -15,6 +15,7 @@ coreapi = "==2.3.3" whitenoise = "==4.1.2" pytz = "==2018.7" drf-yasg = "*" +pyparsing = "==2.4.2" [dev-packages] "flake8" = "*" diff --git a/Pipfile.lock b/Pipfile.lock index a6675b6f..90dc5489 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "648422adf916fcfeff0b93f66fb660e85da82a5fcf4944bc8d53b7cdf4eb5b82" + "sha256": "03fafdda3043ea074c6300a77ce2c6abd9921ccb0273328f9c801f18821510d3" }, "pipfile-spec": 6, "requires": { @@ -152,6 +152,14 @@ ], "version": "==1.1.1" }, + "pyparsing": { + "hashes": [ + "sha256:6f98a7b9397e206d78cc01df10131398f1c8b8510a2f4d97d9abd82e1aacdd80", + "sha256:d9338df12903bbf5d65a0e4e87c2161968b10d2e489652bb47001d82a9b028b4" + ], + "index": "pypi", + "version": "==2.4.2" + }, "python-decouple": { "hashes": [ "sha256:1317df14b43efee4337a4aa02914bf004f010cd56d6c4bd894e6474ec8c4fe2d" @@ -177,26 +185,35 @@ }, "ruamel.yaml": { "hashes": [ - "sha256:08aaaa74ff66565024ecabf9ba2db212712382a21c0458f9a91c623a1fa83b34", - "sha256:23f2efb872d2ebe3d5428b4f1a8f30cbf59f56e780c4981c155411ee65572673", - "sha256:38718e69270141c403b5fc539f774ed394568f8a5195b507991f5b690356facb", - "sha256:44da2be1153e173f90ad8775d4ac4237a3c06cfbb9660c1c1980271621833faa", - "sha256:4b1674a936cdae9735578d4fd64bcbc6cfbb77a1a8f7037a50c6e3874ba4c9d8", - "sha256:51d49c870aca850e652e2cd1c9bea9b52b77d13ad52b0556de496c1d264ea65f", - "sha256:63dc8c6147a4cf77efadf2ae0f34e89e03de79289298bb941b7ae333d5d4020b", - "sha256:6672798c6b52a976a7b24e20665055852388c83198d88029d3c76e2197ac221a", - "sha256:6b6025f9b6a557e15e9fdfda4d9af0b57cd8d59ff98e23a0097ab2d7c0540f07", - "sha256:7b750252e3d1ec5b53d03be508796c04a907060900c7d207280b7456650ebbfc", - "sha256:847177699994f9c31adf78d1ef1ff8f069ef0241e744a3ee8b30fbdaa914cc1e", - "sha256:8e42f3067a59e819935a2926e247170ed93c8f0b2ab64526f888e026854db2e4", - "sha256:922d9e483c05d9000256640026f277fcc0c2e1e9271d05acada8e6cfb4c8b721", - "sha256:92a8ca79f9173cca29ca9663b49d9c936aefc4c8a76f39318b0218c8f3626438", - "sha256:ab8eeca4de4decf0d0a42cb6949d354da9fc70a2d9201f0dd55186c599b2e3a5", - "sha256:bd4b60b649f4a81086f70cd56eff4722018ef36a28094c396f1a53bf450bd579", - "sha256:fc6471ef15b69e454cca82433ac5f84929d9f3e2d72b9e54b06850b6b7133cc0", - "sha256:ffc89770339191acbe5a15041950b5ad9daec7d659619b0ed9dad8c9c80c26f3" - ], - "version": "==0.15.100" + "sha256:4c1dbad22790b5ea8587c2a0cae97ebc7a9d0d88de5d0edb70dea2eab7d8534a", + "sha256:eb4b1ffd095785c50f110118cb6f7bb9cd011ecc013b014436d38b7f8fb7afa9" + ], + "version": "==0.16.0" + }, + "ruamel.yaml.clib": { + "hashes": [ + "sha256:32c37bdc7ee5fbc5e794b497b98f98ecc12e1f1541cdd3bbd65f8ec32e0270d2", + "sha256:385b70734435d2f66f00823d4e224c1a4b53dfeaf9ded3a655a6a2f9c229b1f6", + "sha256:4040ddea350698138e341395508b8dd7610b2312177cb41c8db2b6260adee348", + "sha256:4dc088e55e0cc3f8c18652e830e3ecff159425f01327de4d94e5ce473fdcd2f8", + "sha256:53768934bc28ce07ca82c02d9db6717ae9bad4cdf9511d3a3e6d1b576235d04e", + "sha256:53fd2ef53be8301707662f4c353731d97a4cb2b372972b7dcd73ef245dbab9e9", + "sha256:5712728e6ba56d3b93f5f99a175760c778420caae714687592548c4f7699782e", + "sha256:66df3233e5cca3528be2a700f2a54e26262dde6d5e22b34953e7f44785857c8c", + "sha256:750a15f07178d91204ce4baffb16697cef4c8f583495d4f0fec52902dad8e7fc", + "sha256:820ec13201ed5c015dc74ea7087b2c5c56b8aeb51af4b7d7c859e0b45c07f035", + "sha256:8dcab8a09c17a030d046749eb97ed9a81e02bb642d7816e8757fc5a3016af89d", + "sha256:9e1acd628f2bf601fd4df69523476ee4640be8ba7d9aff8f04cd66a1ae07f119", + "sha256:b31bc078c9bac3dbb5855e94eb382aeef23076bf3d1a2d02ee8d91c55567cb08", + "sha256:b7a681e2d6dbd147ec9808cb1a736c1ef96bc2c693f54e0fc01fe0d10409bd88", + "sha256:c1333e8911c29c6e209db117345141d5fcb772464d62cac3e117912a965d9619", + "sha256:d583e7b9646418dff5ee0e36875b3cabc3d0fb925dfdeec239697c583388f9b2", + "sha256:da610ff9feeb075641128ce40881d2ac3c8e57e7ea04636169b0c3b5e8f711f7", + "sha256:e9b6ebb62806817b01e9eea9fc7da57c12557e44e94e79f5fa82eca4bc7fad60", + "sha256:f36035f1c0b6a7a20010e98b582d38272514a77f34cd45ec0d2847abaa89ac78" + ], + "markers": "platform_python_implementation == 'CPython' and python_version < '3.8'", + "version": "==0.1.0" }, "six": { "hashes": [ @@ -238,6 +255,13 @@ "markers": "sys_platform == 'darwin'", "version": "==0.1.0" }, + "attrs": { + "hashes": [ + "sha256:69c0dbf2ed392de1cb5ec704444b08a5ef81680a61cb899dc08127123af36a79", + "sha256:f0b870f674851ecbfbbbd364d6b5cbdff9dcedbc7f3f5e18a6891057f21fe399" + ], + "version": "==19.1.0" + }, "autopep8": { "hashes": [ "sha256:4d8eec30cc81bc5617dbf1218201d770dc35629363547f17577c61683ccfb3ee" @@ -254,40 +278,41 @@ }, "coverage": { "hashes": [ - "sha256:3684fabf6b87a369017756b551cef29e505cb155ddb892a7a29277b978da88b9", - "sha256:39e088da9b284f1bd17c750ac672103779f7954ce6125fd4382134ac8d152d74", - "sha256:3c205bc11cc4fcc57b761c2da73b9b72a59f8d5ca89979afb0c1c6f9e53c7390", - "sha256:465ce53a8c0f3a7950dfb836438442f833cf6663d407f37d8c52fe7b6e56d7e8", - "sha256:48020e343fc40f72a442c8a1334284620f81295256a6b6ca6d8aa1350c763bbe", - "sha256:5296fc86ab612ec12394565c500b412a43b328b3907c0d14358950d06fd83baf", - "sha256:5f61bed2f7d9b6a9ab935150a6b23d7f84b8055524e7be7715b6513f3328138e", - "sha256:68a43a9f9f83693ce0414d17e019daee7ab3f7113a70c79a3dd4c2f704e4d741", - "sha256:6b8033d47fe22506856fe450470ccb1d8ba1ffb8463494a15cfc96392a288c09", - "sha256:7ad7536066b28863e5835e8cfeaa794b7fe352d99a8cded9f43d1161be8e9fbd", - "sha256:7bacb89ccf4bedb30b277e96e4cc68cd1369ca6841bde7b005191b54d3dd1034", - "sha256:839dc7c36501254e14331bcb98b27002aa415e4af7ea039d9009409b9d2d5420", - "sha256:8f9a95b66969cdea53ec992ecea5406c5bd99c9221f539bca1e8406b200ae98c", - "sha256:932c03d2d565f75961ba1d3cec41ddde00e162c5b46d03f7423edcb807734eab", - "sha256:988529edadc49039d205e0aa6ce049c5ccda4acb2d6c3c5c550c17e8c02c05ba", - "sha256:998d7e73548fe395eeb294495a04d38942edb66d1fa61eb70418871bc621227e", - "sha256:9de60893fb447d1e797f6bf08fdf0dbcda0c1e34c1b06c92bd3a363c0ea8c609", - "sha256:9e80d45d0c7fcee54e22771db7f1b0b126fb4a6c0a2e5afa72f66827207ff2f2", - "sha256:a545a3dfe5082dc8e8c3eb7f8a2cf4f2870902ff1860bd99b6198cfd1f9d1f49", - "sha256:a5d8f29e5ec661143621a8f4de51adfb300d7a476224156a39a392254f70687b", - "sha256:aca06bfba4759bbdb09bf52ebb15ae20268ee1f6747417837926fae990ebc41d", - "sha256:bb23b7a6fd666e551a3094ab896a57809e010059540ad20acbeec03a154224ce", - "sha256:bfd1d0ae7e292105f29d7deaa9d8f2916ed8553ab9d5f39ec65bcf5deadff3f9", - "sha256:c62ca0a38958f541a73cf86acdab020c2091631c137bd359c4f5bddde7b75fd4", - "sha256:c709d8bda72cf4cd348ccec2a4881f2c5848fd72903c185f363d361b2737f773", - "sha256:c968a6aa7e0b56ecbd28531ddf439c2ec103610d3e2bf3b75b813304f8cb7723", - "sha256:df785d8cb80539d0b55fd47183264b7002077859028dfe3070cf6359bf8b2d9c", - "sha256:f406628ca51e0ae90ae76ea8398677a921b36f0bd71aab2099dfed08abd0322f", - "sha256:f46087bbd95ebae244a0eda01a618aff11ec7a069b15a3ef8f6b520db523dcf1", - "sha256:f8019c5279eb32360ca03e9fac40a12667715546eed5c5eb59eb381f2f501260", - "sha256:fc5f4d209733750afd2714e9109816a29500718b32dd9a5db01c0cb3a019b96a" + "sha256:08907593569fe59baca0bf152c43f3863201efb6113ecb38ce7e97ce339805a6", + "sha256:0be0f1ed45fc0c185cfd4ecc19a1d6532d72f86a2bac9de7e24541febad72650", + "sha256:141f08ed3c4b1847015e2cd62ec06d35e67a3ac185c26f7635f4406b90afa9c5", + "sha256:19e4df788a0581238e9390c85a7a09af39c7b539b29f25c89209e6c3e371270d", + "sha256:23cc09ed395b03424d1ae30dcc292615c1372bfba7141eb85e11e50efaa6b351", + "sha256:245388cda02af78276b479f299bbf3783ef0a6a6273037d7c60dc73b8d8d7755", + "sha256:331cb5115673a20fb131dadd22f5bcaf7677ef758741312bee4937d71a14b2ef", + "sha256:386e2e4090f0bc5df274e720105c342263423e77ee8826002dcffe0c9533dbca", + "sha256:3a794ce50daee01c74a494919d5ebdc23d58873747fa0e288318728533a3e1ca", + "sha256:60851187677b24c6085248f0a0b9b98d49cba7ecc7ec60ba6b9d2e5574ac1ee9", + "sha256:63a9a5fc43b58735f65ed63d2cf43508f462dc49857da70b8980ad78d41d52fc", + "sha256:6b62544bb68106e3f00b21c8930e83e584fdca005d4fffd29bb39fb3ffa03cb5", + "sha256:6ba744056423ef8d450cf627289166da65903885272055fb4b5e113137cfa14f", + "sha256:7494b0b0274c5072bddbfd5b4a6c6f18fbbe1ab1d22a41e99cd2d00c8f96ecfe", + "sha256:826f32b9547c8091679ff292a82aca9c7b9650f9fda3e2ca6bf2ac905b7ce888", + "sha256:93715dffbcd0678057f947f496484e906bf9509f5c1c38fc9ba3922893cda5f5", + "sha256:9a334d6c83dfeadae576b4d633a71620d40d1c379129d587faa42ee3e2a85cce", + "sha256:af7ed8a8aa6957aac47b4268631fa1df984643f07ef00acd374e456364b373f5", + "sha256:bf0a7aed7f5521c7ca67febd57db473af4762b9622254291fbcbb8cd0ba5e33e", + "sha256:bf1ef9eb901113a9805287e090452c05547578eaab1b62e4ad456fcc049a9b7e", + "sha256:c0afd27bc0e307a1ffc04ca5ec010a290e49e3afbe841c5cafc5c5a80ecd81c9", + "sha256:dd579709a87092c6dbee09d1b7cfa81831040705ffa12a1b248935274aee0437", + "sha256:df6712284b2e44a065097846488f66840445eb987eb81b3cc6e4149e7b6982e1", + "sha256:e07d9f1a23e9e93ab5c62902833bf3e4b1f65502927379148b6622686223125c", + "sha256:e2ede7c1d45e65e209d6093b762e98e8318ddeff95317d07a27a2140b80cfd24", + "sha256:e4ef9c164eb55123c62411f5936b5c2e521b12356037b6e1c2617cef45523d47", + "sha256:eca2b7343524e7ba246cab8ff00cab47a2d6d54ada3b02772e908a45675722e2", + "sha256:eee64c616adeff7db37cc37da4180a3a5b6177f5c46b187894e633f088fb5b28", + "sha256:ef824cad1f980d27f26166f86856efe11eff9912c4fed97d3804820d43fa550c", + "sha256:efc89291bd5a08855829a3c522df16d856455297cf35ae827a37edac45f466a7", + "sha256:fa964bae817babece5aa2e8c1af841bebb6d0b9add8e637548809d040443fee0", + "sha256:ff37757e068ae606659c28c3bd0d923f9d29a85de79bf25b2b34b148473b5025" ], "index": "pypi", - "version": "==4.5.3" + "version": "==4.5.4" }, "decorator": { "hashes": [ @@ -313,11 +338,11 @@ }, "ipython": { "hashes": [ - "sha256:11067ab11d98b1e6c7f0993506f7a5f8a91af420f7e82be6575fcb7a6ca372a0", - "sha256:60bc55c2c1d287161191cc2469e73c116d9b634cff25fe214a43cba7cec94c79" + "sha256:1d3a1692921e932751bc1a1f7bb96dc38671eeefdc66ed33ee4cbc57e92a410e", + "sha256:537cd0176ff6abd06ef3e23f2d0c4c2c8a4d9277b7451544c6cbf56d1c79a83d" ], "index": "pypi", - "version": "==7.6.1" + "version": "==7.7.0" }, "ipython-genutils": { "hashes": [ @@ -342,11 +367,11 @@ }, "packaging": { "hashes": [ - "sha256:0c98a5d0be38ed775798ece1b9727178c4469d9c3b4ada66e8e6b7849f8732af", - "sha256:9e1cbf8c12b1f1ce0bb5344b8d7ecf66a6f8a6e91bcb0c84593ed6d3ab5c4ab3" + "sha256:a7ac867b97fdc07ee80a8058fe4435ccd274ecc3b0ed61d852d7d53055528cf9", + "sha256:c491ca87294da7cc01902edbe30a5bc6c4c28172b5138ab4e4aa1b9d7bfaeafe" ], "index": "pypi", - "version": "==19.0" + "version": "==19.1" }, "parso": { "hashes": [ @@ -408,10 +433,11 @@ }, "pyparsing": { "hashes": [ - "sha256:530d8bf8cc93a34019d08142593cf4d78a05c890da8cf87ffa3120af53772238", - "sha256:f78e99616b6f1a4745c0580e170251ef1bbafc0d0513e270c4bd281bf29d2800" + "sha256:6f98a7b9397e206d78cc01df10131398f1c8b8510a2f4d97d9abd82e1aacdd80", + "sha256:d9338df12903bbf5d65a0e4e87c2161968b10d2e489652bb47001d82a9b028b4" ], - "version": "==2.4.1" + "index": "pypi", + "version": "==2.4.2" }, "six": { "hashes": [ From a06911cb1d911c12a7dd0220187e6f39764ff59f Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Wed, 7 Aug 2019 14:45:17 -0300 Subject: [PATCH 095/207] Migrate Repository Category v1 to v2 --- bothub/api/v1/views.py | 6 ++++++ bothub/api/v2/repository/views.py | 13 +++++++++++++ bothub/api/v2/routers.py | 15 ++++++++++----- 3 files changed, 29 insertions(+), 5 deletions(-) diff --git a/bothub/api/v1/views.py b/bothub/api/v1/views.py index 8f15eb62..b9a0ed47 100644 --- a/bothub/api/v1/views.py +++ b/bothub/api/v1/views.py @@ -952,6 +952,12 @@ class UserProfileViewSet( lookup_field = 'nickname' +@method_decorator( + name='list', + decorator=swagger_auto_schema( + deprecated=True, + ) +) class Categories( mixins.ListModelMixin, GenericViewSet): diff --git a/bothub/api/v2/repository/views.py b/bothub/api/v2/repository/views.py index f4379cdc..c1d1c27f 100644 --- a/bothub/api/v2/repository/views.py +++ b/bothub/api/v2/repository/views.py @@ -11,12 +11,14 @@ from bothub.common.models import Repository from bothub.common.models import RepositoryVote from bothub.common.models import RepositoryAuthorization +from bothub.common.models import RepositoryCategory from ..metadata import Metadata from .serializers import RepositorySerializer from .serializers import RepositoryContributionsSerializer from .serializers import RepositoryVotesSerializer from .serializers import ShortRepositorySerializer +from .serializers import RepositoryCategorySerializer from .permissions import RepositoryPermission from .filters import RepositoriesFilter @@ -164,3 +166,14 @@ def get_queryset(self): ) else: return self.queryset.none() + + +class RepositoryCategoriesView( + mixins.ListModelMixin, + GenericViewSet): + """ + List all categories. + """ + serializer_class = RepositoryCategorySerializer + queryset = RepositoryCategory.objects.all() + pagination_class = None diff --git a/bothub/api/v2/routers.py b/bothub/api/v2/routers.py index 80147f87..b62a41a8 100644 --- a/bothub/api/v2/routers.py +++ b/bothub/api/v2/routers.py @@ -4,6 +4,7 @@ from .repository.views import RepositoryVotesViewSet from .repository.views import RepositoriesViewSet from .repository.views import RepositoriesContributionsViewSet +from .repository.views import RepositoryCategoriesView from .examples.views import ExamplesViewSet from .evaluate.views import EvaluateViewSet from .evaluate.views import ResultsListViewSet @@ -86,11 +87,15 @@ def get_lookup_regex(self, viewset, lookup_prefix=''): router = Router() -router.register('repository', RepositoryViewSet) -router.register('repository-votes', RepositoryVotesViewSet) -router.register('repositories', RepositoriesViewSet) -router.register('repositories-contributions', RepositoriesContributionsViewSet) -router.register('examples', ExamplesViewSet) +router.register('repository/repository', RepositoryViewSet) +router.register('repository/repository-votes', RepositoryVotesViewSet) +router.register('repository/repositories', RepositoriesViewSet) +router.register( + 'repository/repositories-contributions', + RepositoriesContributionsViewSet +) +router.register('repository/categories', RepositoryCategoriesView) +router.register('repository/examples', ExamplesViewSet) router.register('evaluate/results', ResultsListViewSet) router.register('evaluate', EvaluateViewSet) router.register('account/login', LoginViewSet) From 84603b4e9a660bbac03d2f739c5873bb58114646 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Wed, 7 Aug 2019 14:51:15 -0300 Subject: [PATCH 096/207] Added test Repository Category --- bothub/api/v2/tests/test_repository.py | 38 ++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/bothub/api/v2/tests/test_repository.py b/bothub/api/v2/tests/test_repository.py index ec41e234..77e1ffc5 100644 --- a/bothub/api/v2/tests/test_repository.py +++ b/bothub/api/v2/tests/test_repository.py @@ -20,6 +20,7 @@ from bothub.api.v2.repository.views import RepositoriesContributionsViewSet from bothub.api.v2.repository.views import RepositoriesViewSet from bothub.api.v2.repository.views import RepositoryVotesViewSet +from bothub.api.v2.repository.views import RepositoryCategoriesView from bothub.api.v2.repository.serializers import RepositorySerializer @@ -856,3 +857,40 @@ def test_okay(self): len(content_data['results']), 1 ) + + +class CategoriesTestCase(TestCase): + def setUp(self): + self.factory = RequestFactory() + + self.category = RepositoryCategory.objects.create(name='Category 1') + self.business_category = RepositoryCategory.objects.create( + name='Business', + icon='business') + + def request(self): + request = self.factory.get('/v2/repository/categories/') + response = RepositoryCategoriesView.as_view( + {'get': 'list'})(request) + response.render() + content_data = json.loads(response.content) + return (response, content_data,) + + def test_default_category_icon(self): + response, content_data = self.request() + self.assertEqual( + content_data[0].get('id'), + self.category.id) + self.assertEqual( + content_data[0].get('icon'), + 'botinho') + + def test_custom_category_icon(self): + response, content_data = self.request() + self.assertEqual( + content_data[1].get('id'), + self.business_category.id) + self.assertEqual( + content_data[1].get('icon'), + self.business_category.icon) + From 3564382ca3f8d6bf771c4b7e9ce5f5c03dceeb34 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Wed, 7 Aug 2019 15:33:29 -0300 Subject: [PATCH 097/207] Migrate Search Repositories v1 to v2 --- bothub/api/v1/views.py | 3 +- bothub/api/v2/repository/views.py | 38 +++++++++++++++++ bothub/api/v2/routers.py | 2 + bothub/api/v2/tests/test_repository.py | 56 +++++++++++++++++++++++++- 4 files changed, 97 insertions(+), 2 deletions(-) diff --git a/bothub/api/v1/views.py b/bothub/api/v1/views.py index b9a0ed47..57f4a4b7 100644 --- a/bothub/api/v1/views.py +++ b/bothub/api/v1/views.py @@ -415,7 +415,8 @@ def create(self, request, *args, **kwargs): description='Nickname User to find repositories', type=openapi.TYPE_STRING ), - ] + ], + deprecated=True ) ) class SearchRepositoriesViewSet( diff --git a/bothub/api/v2/repository/views.py b/bothub/api/v2/repository/views.py index c1d1c27f..c4aba86c 100644 --- a/bothub/api/v2/repository/views.py +++ b/bothub/api/v2/repository/views.py @@ -177,3 +177,41 @@ class RepositoryCategoriesView( serializer_class = RepositoryCategorySerializer queryset = RepositoryCategory.objects.all() pagination_class = None + + +@method_decorator( + name='list', + decorator=swagger_auto_schema( + manual_parameters=[ + openapi.Parameter( + 'nickname', + openapi.IN_QUERY, + description='Nickname User to find repositories', + type=openapi.TYPE_STRING + ), + ] + ) +) +class SearchRepositoriesViewSet( + mixins.ListModelMixin, + GenericViewSet): + """ + List all user's repositories + """ + queryset = Repository.objects + serializer_class = RepositorySerializer + lookup_field = 'nickname' + + def get_queryset(self, *args, **kwargs): + try: + if self.request.query_params.get('nickname', None): + return self.queryset.filter( + owner__nickname=self.request.query_params.get( + 'nickname', + self.request.user + ) + ) + else: + return self.queryset.filter(owner=self.request.user) + except TypeError: + return self.queryset.none() diff --git a/bothub/api/v2/routers.py b/bothub/api/v2/routers.py index b62a41a8..2aa8f354 100644 --- a/bothub/api/v2/routers.py +++ b/bothub/api/v2/routers.py @@ -5,6 +5,7 @@ from .repository.views import RepositoriesViewSet from .repository.views import RepositoriesContributionsViewSet from .repository.views import RepositoryCategoriesView +from .repository.views import SearchRepositoriesViewSet from .examples.views import ExamplesViewSet from .evaluate.views import EvaluateViewSet from .evaluate.views import ResultsListViewSet @@ -96,6 +97,7 @@ def get_lookup_regex(self, viewset, lookup_prefix=''): ) router.register('repository/categories', RepositoryCategoriesView) router.register('repository/examples', ExamplesViewSet) +router.register('repository/search-repositories', SearchRepositoriesViewSet) router.register('evaluate/results', ResultsListViewSet) router.register('evaluate', EvaluateViewSet) router.register('account/login', LoginViewSet) diff --git a/bothub/api/v2/tests/test_repository.py b/bothub/api/v2/tests/test_repository.py index 77e1ffc5..cba2aaa5 100644 --- a/bothub/api/v2/tests/test_repository.py +++ b/bothub/api/v2/tests/test_repository.py @@ -1,4 +1,5 @@ import json +import uuid from django.test import TestCase from django.test import RequestFactory @@ -21,6 +22,7 @@ from bothub.api.v2.repository.views import RepositoriesViewSet from bothub.api.v2.repository.views import RepositoryVotesViewSet from bothub.api.v2.repository.views import RepositoryCategoriesView +from bothub.api.v2.repository.views import SearchRepositoriesViewSet from bothub.api.v2.repository.serializers import RepositorySerializer @@ -857,7 +859,7 @@ def test_okay(self): len(content_data['results']), 1 ) - + class CategoriesTestCase(TestCase): def setUp(self): @@ -894,3 +896,55 @@ def test_custom_category_icon(self): content_data[1].get('icon'), self.business_category.icon) + +class SearchRepositoriesTestCase(TestCase): + def setUp(self): + self.factory = RequestFactory() + + self.owner, self.owner_token = create_user_and_token('owner') + self.user, self.user_token = create_user_and_token() + + self.category = RepositoryCategory.objects.create( + name='ID') + + self.repository = Repository.objects.create( + owner=self.owner, + name='Testing', + slug='test', + language=languages.LANGUAGE_EN) + self.repository.categories.add(self.category) + + def request(self, nickname): + request = self.factory.get( + '/v2/repository/search-repositories/?nickname={}'.format(nickname) + ) + response = SearchRepositoriesViewSet.as_view( + {'get': 'list'} + )(request, nickname=nickname) + response.render() + content_data = json.loads(response.content) + return (response, content_data,) + + def test_okay(self): + response, content_data = self.request('owner') + self.assertEqual(response.status_code, 200) + self.assertEqual( + content_data.get('count'), + 1) + self.assertEqual( + uuid.UUID(content_data.get('results')[0].get('uuid')), + self.repository.uuid) + + def test_empty_with_user_okay(self): + response, content_data = self.request('fake') + self.assertEqual(response.status_code, 200) + self.assertEqual( + content_data.get('count'), + 0) + + def test_empty_without_user_okay(self): + response, content_data = self.request('') + self.assertEqual(response.status_code, 200) + self.assertEqual( + content_data.get('count'), + 0) From dc905bc8ebf67af15e294fd3286dad42053ed401 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Wed, 7 Aug 2019 16:20:00 -0300 Subject: [PATCH 098/207] Added pragma no coveralls --- bothub/api/v2/fields.py | 6 +++--- bothub/api/v2/metadata.py | 8 ++++---- bothub/api/v2/views.py | 2 +- bothub/authentication/models.py | 4 ++-- bothub/common/admin.py | 2 +- bothub/common/views.py | 2 +- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/bothub/api/v2/fields.py b/bothub/api/v2/fields.py index b41552d3..29895512 100644 --- a/bothub/api/v2/fields.py +++ b/bothub/api/v2/fields.py @@ -36,10 +36,10 @@ def __init__(self, *args, validators=[], **kwargs): **kwargs) def to_representation(self, obj): - return obj.value + return obj.value # pragma: no cover -class LabelValueField(serializers.CharField): +class LabelValueField(serializers.CharField): # pragma: no cover def __init__(self, *args, validators=[], **kwargs): kwargs.pop('max_length', 0) kwargs.pop('help_text', '') @@ -53,4 +53,4 @@ def __init__(self, *args, validators=[], **kwargs): **kwargs) def to_representation(self, obj): - return obj.value + return obj.value # pragma: no cover diff --git a/bothub/api/v2/metadata.py b/bothub/api/v2/metadata.py index 6a0f707c..7b431c55 100644 --- a/bothub/api/v2/metadata.py +++ b/bothub/api/v2/metadata.py @@ -42,7 +42,7 @@ class Metadata(BaseMetadata): EntityText: 'entity text', }) - def determine_metadata(self, request, view): + def determine_metadata(self, request, view): # pragma: no cover metadata = OrderedDict() metadata['name'] = view.get_view_name() metadata['description'] = view.get_view_description() @@ -60,7 +60,7 @@ def determine_metadata(self, request, view): metadata['actions'] = actions return metadata - def determine_actions(self, request, view): + def determine_actions(self, request, view): # pragma: no cover actions = {} for method in {'PUT', 'POST'} & set(view.allowed_methods): serializer = view.get_serializer() @@ -68,7 +68,7 @@ def determine_actions(self, request, view): view.request = request return actions - def get_serializer_info(self, serializer): + def get_serializer_info(self, serializer): # pragma: no cover if hasattr(serializer, 'child'): serializer = serializer.child return OrderedDict([ @@ -76,7 +76,7 @@ def get_serializer_info(self, serializer): for field_name, field in serializer.fields.items() ]) - def get_field_info(self, field): + def get_field_info(self, field): # pragma: no cover field_info = OrderedDict() field_info['type'] = self.label_lookup[field] or 'field' field_info['required'] = getattr(field, 'required', False) diff --git a/bothub/api/v2/views.py b/bothub/api/v2/views.py index dbf0b5ac..f757a426 100644 --- a/bothub/api/v2/views.py +++ b/bothub/api/v2/views.py @@ -4,6 +4,6 @@ from bothub.common.models import Repository -def repository_shortcut(self, **kwargs): +def repository_shortcut(self, **kwargs): # pragma: no cover repository = get_object_or_404(Repository, **kwargs) return redirect('repository-detail', uuid=repository.uuid) diff --git a/bothub/authentication/models.py b/bothub/authentication/models.py index 922b3eea..ab2de30a 100644 --- a/bothub/authentication/models.py +++ b/bothub/authentication/models.py @@ -104,7 +104,7 @@ def token_generator(self): def send_welcome_email(self): if not settings.SEND_EMAILS: - return False + return False # pragma: no cover context = { 'name': self.name, } @@ -124,7 +124,7 @@ def make_password_reset_token(self): def send_reset_password_email(self): if not settings.SEND_EMAILS: - return False + return False # pragma: no cover token = self.make_password_reset_token() reset_url = '{}reset-password/{}/{}/'.format( settings.BOTHUB_WEBAPP_BASE_URL, diff --git a/bothub/common/admin.py b/bothub/common/admin.py index e8e68ed1..7d8d39c5 100644 --- a/bothub/common/admin.py +++ b/bothub/common/admin.py @@ -28,7 +28,7 @@ class RepositoryUpdateInline(admin.TabularInline): readonly_fields = fields def download_bot_data(self, obj): - if not obj.trained_at: + if not obj.trained_at: # pragma: no cover return '-' return format_html(""" Download Bot Data diff --git a/bothub/common/views.py b/bothub/common/views.py index 4ff4e870..7a9d7cf2 100644 --- a/bothub/common/views.py +++ b/bothub/common/views.py @@ -6,7 +6,7 @@ @staff_member_required -def download_bot_data(self, update_id): +def download_bot_data(self, update_id): # pragma: no cover update = get_object_or_404(RepositoryUpdate, id=update_id) if not update.trained_at: raise ValidationError('Update #{} not trained at.'.format(update.id)) From d974054967004967385f17fe5c89a915213be4f2 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Wed, 7 Aug 2019 16:35:24 -0300 Subject: [PATCH 099/207] Added pragma no coveralls --- bothub/common/languages.py | 4 ++-- bothub/common/models.py | 44 +++++++++++++++++++------------------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/bothub/common/languages.py b/bothub/common/languages.py index 8a4d201e..087b02bd 100644 --- a/bothub/common/languages.py +++ b/bothub/common/languages.py @@ -89,11 +89,11 @@ ] -def is_valid_language(value): +def is_valid_language(value): # pragma: no cover return value in settings.SUPPORTED_LANGUAGES.keys() -def validate_language(value): +def validate_language(value): # pragma: no cover if not is_valid_language(value): raise ValidationError(_( '{} is not a supported language.').format(value)) diff --git a/bothub/common/models.py b/bothub/common/models.py index b06e7c5f..e5179a70 100644 --- a/bothub/common/models.py +++ b/bothub/common/models.py @@ -184,7 +184,7 @@ class Meta: @classmethod def request_nlp_train(cls, user_authorization): - try: + try: # pragma: no cover r = requests.post( # pragma: no cover cls.nlp_train_url, data={}, @@ -198,7 +198,7 @@ def request_nlp_train(cls, user_authorization): @classmethod def request_nlp_analyze(cls, user_authorization, data): - try: + try: # pragma: no cover r = requests.post( # pragma: no cover cls.nlp_analyze_url, data={ @@ -344,7 +344,7 @@ def __str__(self): self.name, self.owner.nickname, self.slug, - ) + ) # pragma: no cover def examples(self, language=None, exclude_deleted=True, queryset=None): if queryset is None: @@ -368,7 +368,7 @@ def evaluations(self, language=None, exclude_deleted=True, queryset=None): repository_update__language=language) if exclude_deleted: return query.exclude(deleted_in__isnull=False) - return query + return query # pragma: no cover def evaluations_results(self, queryset=None): if queryset is None: @@ -515,9 +515,9 @@ def examples(self): def requirements_to_train(self): try: self.validate_init_train() - except RepositoryUpdateAlreadyTrained: + except RepositoryUpdateAlreadyTrained: # pragma: no cover return [_('This bot version has already been trained.')] - except RepositoryUpdateAlreadyStartedTraining: + except RepositoryUpdateAlreadyStartedTraining: # pragma: no cover return [_('This bot version is being trained.')] r = [] @@ -557,7 +557,7 @@ def requirements_to_train(self): @property def ready_for_train(self): if self.training_started_at: - return False + return False # pragma: no cover if len(self.requirements_to_train) > 0: return False @@ -608,7 +608,7 @@ def use_language_model_featurizer(self): return self.algorithm != Repository.ALGORITHM_NEURAL_NETWORK_INTERNAL def __str__(self): - return 'Repository Update #{}'.format(self.id) + return 'Repository Update #{}'.format(self.id) # pragma: no cover def validate_init_train(self, by=None): if self.trained_at: @@ -693,7 +693,7 @@ class Meta: def language(self): return self.repository_update.language - def has_valid_entities(self, language=None): + def has_valid_entities(self, language=None): # pragma: no cover if not language or language == self.repository_update.language: return True return self.get_translation(language).has_valid_entities @@ -704,7 +704,7 @@ def get_translation(self, language): except RepositoryTranslatedExample.DoesNotExist: raise DoesNotHaveTranslation() - def get_text(self, language=None): + def get_text(self, language=None): # pragma: no cover if not language or language == self.repository_update.language: return self.text return self.get_translation(language).text @@ -843,7 +843,7 @@ class Meta: objects = RepositoryEntityLabelManager() - def examples(self, exclude_deleted=True): + def examples(self, exclude_deleted=True): # pragma: no cover return self.repository.examples( exclude_deleted=exclude_deleted).filter( entities__entity__label=self) @@ -857,7 +857,7 @@ def get(self, repository, value, create_entity=True): value=value) except self.model.DoesNotExist: if not create_entity: - raise self.model.DoesNotExist + raise self.model.DoesNotExist # pragma: no cover return super().create( repository=repository, @@ -1075,7 +1075,7 @@ def level(self): if self.role == RepositoryAuthorization.ROLE_ADMIN: return RepositoryAuthorization.LEVEL_ADMIN - return RepositoryAuthorization.LEVEL_NOTHING + return RepositoryAuthorization.LEVEL_NOTHING # pragma: no cover @property def can_read(self): @@ -1106,8 +1106,8 @@ def is_admin(self): def is_owner(self): try: user = self.user - except User.DoesNotExist: - return False + except User.DoesNotExist: # pragma: no cover + return False # pragma: no cover return self.repository.owner == user @property @@ -1116,7 +1116,7 @@ def role_verbose(self): def send_new_role_email(self, responsible=None): if not settings.SEND_EMAILS: - return False + return False # pragma: no cover responsible_name = responsible and responsible.name \ or self.repository.owner.name context = { @@ -1188,7 +1188,7 @@ class Meta: def send_new_request_email_to_admins(self): if not settings.SEND_EMAILS: - return False + return False # pragma: no cover context = { 'user_name': self.user.name, 'repository_name': self.repository.name, @@ -1210,7 +1210,7 @@ def send_new_request_email_to_admins(self): def send_request_rejected_email(self): if not settings.SEND_EMAILS: - return False + return False # pragma: no cover context = { 'repository_name': self.repository.name, } @@ -1228,7 +1228,7 @@ def send_request_rejected_email(self): def send_request_approved_email(self): if not settings.SEND_EMAILS: - return False + return False # pragma: no cover context = { 'admin_name': self.approved_by.name, 'repository_name': self.repository.name, @@ -1281,12 +1281,12 @@ class Meta: def language(self): return self.repository_update.language - def get_text(self, language=None): + def get_text(self, language=None): # pragma: no cover if not language or language == self.repository_update.language: return self.text return None - def get_entities(self, language): + def get_entities(self, language): # pragma: no cover if not language or language == self.repository_update.language: return self.entities.all() return None @@ -1311,7 +1311,7 @@ class Meta: editable=False, help_text=_('evaluate object')) - def get_evaluate(self): + def get_evaluate(self): # pragma: no cover return self.repository_evaluate From 38565b66c21c4a8775b6ab705995424ef173a5bf Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Thu, 8 Aug 2019 09:26:50 -0300 Subject: [PATCH 100/207] Added pragma no coveralls --- bothub/common/models.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bothub/common/models.py b/bothub/common/models.py index e5179a70..70f60ffa 100644 --- a/bothub/common/models.py +++ b/bothub/common/models.py @@ -709,7 +709,7 @@ def get_text(self, language=None): # pragma: no cover return self.text return self.get_translation(language).text - def get_entities(self, language): + def get_entities(self, language): # pragma: no cover if not language or language == self.repository_update.language: return self.entities.all() return self.get_translation(language).entities.all() @@ -903,7 +903,7 @@ def set_label(self, value): value=value) -class EntityBaseQueryset(models.QuerySet): +class EntityBaseQueryset(models.QuerySet): # pragma: no cover def create(self, entity, **kwargs): if type(entity) is not RepositoryEntity: instance = self.model(**kwargs) @@ -960,7 +960,7 @@ def value(self): return self.example.text[self.start:self.end] @property - def rasa_nlu_data(self): + def rasa_nlu_data(self): # pragma: no cover return { 'start': self.start, 'end': self.end, From 265a7ac3669ca1bbf2ba55fd1349e7cc9c86a7f3 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Thu, 8 Aug 2019 09:42:10 -0300 Subject: [PATCH 101/207] Added pragma no coveralls --- bothub/common/admin.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bothub/common/admin.py b/bothub/common/admin.py index 7d8d39c5..03091a1b 100644 --- a/bothub/common/admin.py +++ b/bothub/common/admin.py @@ -27,8 +27,8 @@ class RepositoryUpdateInline(admin.TabularInline): ] readonly_fields = fields - def download_bot_data(self, obj): - if not obj.trained_at: # pragma: no cover + def download_bot_data(self, obj): # pragma: no cover + if not obj.trained_at: return '-' return format_html(""" Download Bot Data From bbf01f65ffaa884e369f3231947aaecef11957a2 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Thu, 8 Aug 2019 10:11:17 -0300 Subject: [PATCH 102/207] Refact RepositoryAuthorizationViewSet Refact RepositoryAuthorizationViewSet and RepositoryAuthorizationRoleViewSet --- bothub/api/v1/views.py | 12 ++++- bothub/api/v2/mixins.py | 20 +++++++++ bothub/api/v2/repository/filters.py | 29 +++++++++++++ bothub/api/v2/repository/permissions.py | 6 +++ bothub/api/v2/repository/serializers.py | 16 +++++++ bothub/api/v2/repository/views.py | 58 ++++++++++++++++++++++++- bothub/api/v2/routers.py | 2 + 7 files changed, 139 insertions(+), 4 deletions(-) create mode 100644 bothub/api/v2/mixins.py diff --git a/bothub/api/v1/views.py b/bothub/api/v1/views.py index 57f4a4b7..fc294a57 100644 --- a/bothub/api/v1/views.py +++ b/bothub/api/v1/views.py @@ -1007,6 +1007,12 @@ class TranslationsViewSet( filter_class = TranslationsFilter +@method_decorator( + name='list', + decorator=swagger_auto_schema( + deprecated=True, + ) +) class RepositoryAuthorizationViewSet( mixins.ListModelMixin, GenericViewSet): @@ -1037,7 +1043,8 @@ class RepositoryAuthorizationViewSet( type=openapi.TYPE_STRING, required=True ), - ] + ], + deprecated=True ) ) @method_decorator( @@ -1058,7 +1065,8 @@ class RepositoryAuthorizationViewSet( type=openapi.TYPE_STRING, required=True ), - ] + ], + deprecated=True ) ) class RepositoryAuthorizationRoleViewSet( diff --git a/bothub/api/v2/mixins.py b/bothub/api/v2/mixins.py new file mode 100644 index 00000000..420659dd --- /dev/null +++ b/bothub/api/v2/mixins.py @@ -0,0 +1,20 @@ +from django.shortcuts import get_object_or_404 + + +class MultipleFieldLookupMixin(object): + """ + Apply this mixin to any view or viewset to get multiple field filtering + based on a `lookup_fields` attribute, instead of the default single field + filtering. + """ + + def get_object(self): + queryset = self.get_queryset() + queryset = self.filter_queryset(queryset) + filter = {} + for field in self.lookup_fields: + if self.kwargs.get(field): + filter[field] = self.kwargs[field] + obj = get_object_or_404(queryset, **filter) + self.check_object_permissions(self.request, obj) + return obj diff --git a/bothub/api/v2/repository/filters.py b/bothub/api/v2/repository/filters.py index 99d8651b..709f801e 100644 --- a/bothub/api/v2/repository/filters.py +++ b/bothub/api/v2/repository/filters.py @@ -1,7 +1,11 @@ from django_filters import rest_framework as filters from django.utils.translation import gettext as _ +from rest_framework.exceptions import PermissionDenied +from rest_framework.exceptions import NotFound +from django.core.exceptions import ValidationError as DjangoValidationError from bothub.common.models import Repository +from bothub.common.models import RepositoryAuthorization class RepositoriesFilter(filters.FilterSet): @@ -19,3 +23,28 @@ class Meta: def filter_language(self, queryset, name, value): return queryset.supported_language(value) + + +class RepositoryAuthorizationFilter(filters.FilterSet): + class Meta: + model = RepositoryAuthorization + fields = ['repository'] + + repository = filters.CharFilter( + field_name='repository', + method='filter_repository_uuid', + help_text=_('Repository\'s UUID')) + + def filter_repository_uuid(self, queryset, name, value): + request = self.request + try: + repository = Repository.objects.get(uuid=value) + authorization = repository.get_user_authorization(request.user) + if not authorization.is_admin: + raise PermissionDenied() + return queryset.filter(repository=repository) + except Repository.DoesNotExist: + raise NotFound( + _('Repository {} does not exist').format(value)) + except DjangoValidationError: + raise NotFound(_('Invalid repository UUID')) diff --git a/bothub/api/v2/repository/permissions.py b/bothub/api/v2/repository/permissions.py index 9b3b006f..f884427e 100644 --- a/bothub/api/v2/repository/permissions.py +++ b/bothub/api/v2/repository/permissions.py @@ -18,3 +18,9 @@ def has_object_permission(self, request, view, obj): return authorization.can_write return authorization.is_admin return False + + +class RepositoryAdminManagerAuthorization(permissions.BasePermission): + def has_object_permission(self, request, view, obj): + authorization = obj.repository.get_user_authorization(request.user) + return authorization.is_admin diff --git a/bothub/api/v2/repository/serializers.py b/bothub/api/v2/repository/serializers.py index 94232b75..7309b510 100644 --- a/bothub/api/v2/repository/serializers.py +++ b/bothub/api/v2/repository/serializers.py @@ -1,4 +1,6 @@ +from django.utils.translation import gettext as _ from rest_framework import serializers +from rest_framework.exceptions import PermissionDenied from bothub.common.models import Repository from bothub.common.models import RepositoryVote @@ -328,3 +330,17 @@ class Meta: 'created_at', ] ref_name = None + + +class RepositoryAuthorizationRoleSerializer(serializers.ModelSerializer): + class Meta: + model = RepositoryAuthorization + fields = [ + 'role', + ] + ref_name = None + + def validate(self, data): + if self.instance.user == self.instance.repository.owner: + raise PermissionDenied(_('The owner role can\'t be changed.')) + return data diff --git a/bothub/api/v2/repository/views.py b/bothub/api/v2/repository/views.py index c4aba86c..dea99ff7 100644 --- a/bothub/api/v2/repository/views.py +++ b/bothub/api/v2/repository/views.py @@ -1,26 +1,34 @@ from django.utils.decorators import method_decorator +from django_filters.rest_framework import DjangoFilterBackend +from django.shortcuts import get_object_or_404 from drf_yasg import openapi from drf_yasg.utils import swagger_auto_schema from rest_framework.response import Response from rest_framework.viewsets import GenericViewSet from rest_framework import mixins, status from rest_framework.permissions import IsAuthenticatedOrReadOnly -from django_filters.rest_framework import DjangoFilterBackend +from rest_framework.permissions import IsAuthenticated from rest_framework.filters import SearchFilter +from bothub.api.v2.mixins import MultipleFieldLookupMixin +from bothub.authentication.models import User from bothub.common.models import Repository from bothub.common.models import RepositoryVote from bothub.common.models import RepositoryAuthorization from bothub.common.models import RepositoryCategory from ..metadata import Metadata -from .serializers import RepositorySerializer +from .serializers import RepositorySerializer, \ + RepositoryAuthorizationRoleSerializer from .serializers import RepositoryContributionsSerializer from .serializers import RepositoryVotesSerializer from .serializers import ShortRepositorySerializer from .serializers import RepositoryCategorySerializer +from .serializers import RepositoryAuthorizationSerializer from .permissions import RepositoryPermission +from .permissions import RepositoryAdminManagerAuthorization from .filters import RepositoriesFilter +from .filters import RepositoryAuthorizationFilter class RepositoryViewSet( @@ -215,3 +223,49 @@ def get_queryset(self, *args, **kwargs): return self.queryset.filter(owner=self.request.user) except TypeError: return self.queryset.none() + + +class RepositoryAuthorizationViewSet( + MultipleFieldLookupMixin, + mixins.UpdateModelMixin, + mixins.ListModelMixin, + GenericViewSet): + queryset = RepositoryAuthorization.objects.exclude( + role=RepositoryAuthorization.ROLE_NOT_SETTED) + serializer_class = RepositoryAuthorizationSerializer + filter_class = RepositoryAuthorizationFilter + lookup_fields = ['repository__uuid', 'user__nickname'] + permission_classes = [ + IsAuthenticated, + ] + + def get_object_update(self): + repository_uuid = self.kwargs.get('repository__uuid') + user_nickname = self.kwargs.get('user__nickname') + + repository = get_object_or_404(Repository, uuid=repository_uuid) + user = get_object_or_404(User, nickname=user_nickname) + + obj = repository.get_user_authorization(user) + + self.check_object_permissions(self.request, obj) + return obj + + def update(self, *args, **kwargs): + self.lookup_field = 'user__nickname' + + self.filter_class = None + self.serializer_class = RepositoryAuthorizationRoleSerializer + self.permission_classes = [ + IsAuthenticated, + RepositoryAdminManagerAuthorization, + ] + response = super().update(*args, **kwargs) + instance = self.get_object_update() + if instance.role is not RepositoryAuthorization.ROLE_NOT_SETTED: + instance.send_new_role_email(self.request.user) + return response + + def list(self, request, *args, **kwargs): + self.lookup_fields = [] + return super().list(request, *args, **kwargs) diff --git a/bothub/api/v2/routers.py b/bothub/api/v2/routers.py index 2aa8f354..6a09c944 100644 --- a/bothub/api/v2/routers.py +++ b/bothub/api/v2/routers.py @@ -6,6 +6,7 @@ from .repository.views import RepositoriesContributionsViewSet from .repository.views import RepositoryCategoriesView from .repository.views import SearchRepositoriesViewSet +from .repository.views import RepositoryAuthorizationViewSet from .examples.views import ExamplesViewSet from .evaluate.views import EvaluateViewSet from .evaluate.views import ResultsListViewSet @@ -98,6 +99,7 @@ def get_lookup_regex(self, viewset, lookup_prefix=''): router.register('repository/categories', RepositoryCategoriesView) router.register('repository/examples', ExamplesViewSet) router.register('repository/search-repositories', SearchRepositoriesViewSet) +router.register('repository/authorizations', RepositoryAuthorizationViewSet) router.register('evaluate/results', ResultsListViewSet) router.register('evaluate', EvaluateViewSet) router.register('account/login', LoginViewSet) From c5e2ebfcc198c5fe2050f369eda78c6bfae771ba Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Thu, 8 Aug 2019 10:14:52 -0300 Subject: [PATCH 103/207] Added test RepositoryAuthorization --- bothub/api/v2/tests/test_repository.py | 142 +++++++++++++++++++++++++ 1 file changed, 142 insertions(+) diff --git a/bothub/api/v2/tests/test_repository.py b/bothub/api/v2/tests/test_repository.py index cba2aaa5..89169682 100644 --- a/bothub/api/v2/tests/test_repository.py +++ b/bothub/api/v2/tests/test_repository.py @@ -23,6 +23,7 @@ from bothub.api.v2.repository.views import RepositoryVotesViewSet from bothub.api.v2.repository.views import RepositoryCategoriesView from bothub.api.v2.repository.views import SearchRepositoriesViewSet +from bothub.api.v2.repository.views import RepositoryAuthorizationViewSet from bothub.api.v2.repository.serializers import RepositorySerializer @@ -948,3 +949,144 @@ def test_empty_without_user_okay(self): self.assertEqual( content_data.get('count'), 0) + + +class ListAuthorizationTestCase(TestCase): + def setUp(self): + self.factory = RequestFactory() + + self.owner, self.owner_token = create_user_and_token('owner') + self.user, self.user_token = create_user_and_token() + + self.repository = Repository.objects.create( + owner=self.owner, + name='Testing', + slug='test', + language=languages.LANGUAGE_EN) + + self.user_auth = self.repository.get_user_authorization(self.user) + self.user_auth.role = RepositoryAuthorization.ROLE_CONTRIBUTOR + self.user_auth.save() + + def request(self, repository, token): + authorization_header = { + 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), + } + request = self.factory.get( + '/v2/repository/authorizations/', + { + 'repository': repository.uuid, + }, + **authorization_header) + response = RepositoryAuthorizationViewSet.as_view( + {'get': 'list'})(request) + response.render() + content_data = json.loads(response.content) + return (response, content_data,) + + def test_okay(self): + response, content_data = self.request( + self.repository, + self.owner_token) + + self.assertEqual( + response.status_code, + status.HTTP_200_OK) + + self.assertEqual( + content_data.get('count'), + 1) + + self.assertEqual( + content_data.get('results')[0].get('user'), + self.user.id) + + def test_user_forbidden(self): + response, content_data = self.request( + self.repository, + self.user_token) + + self.assertEqual( + response.status_code, + status.HTTP_403_FORBIDDEN) + + +class UpdateAuthorizationRoleTestCase(TestCase): + def setUp(self): + self.factory = RequestFactory() + + self.owner, self.owner_token = create_user_and_token('owner') + self.user, self.user_token = create_user_and_token() + + self.repository = Repository.objects.create( + owner=self.owner, + name='Testing', + slug='test', + language=languages.LANGUAGE_EN) + + def request(self, repository, token, user, data): + authorization_header = { + 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), + } + request = self.factory.patch( + '/v2/repository/authorizations/{}/{}/'.format( + repository.uuid, user.nickname), + self.factory._encode_data(data, MULTIPART_CONTENT), + MULTIPART_CONTENT, + **authorization_header) + view = RepositoryAuthorizationViewSet.as_view( + {'patch': 'update'}) + response = view( + request, + repository__uuid=repository.uuid, + user__nickname=user.nickname) + response.render() + content_data = json.loads(response.content) + return (response, content_data,) + + def test_okay(self): + response, content_data = self.request( + self.repository, + self.owner_token, + self.user, + { + 'role': RepositoryAuthorization.ROLE_CONTRIBUTOR, + }) + + self.assertEqual( + response.status_code, + status.HTTP_200_OK) + self.assertEqual( + content_data.get('role'), + RepositoryAuthorization.ROLE_CONTRIBUTOR) + + user_authorization = self.repository.get_user_authorization(self.user) + self.assertEqual( + user_authorization.role, + RepositoryAuthorization.ROLE_CONTRIBUTOR) + + def test_forbidden(self): + response, content_data = self.request( + self.repository, + self.user_token, + self.user, + { + 'role': RepositoryAuthorization.ROLE_CONTRIBUTOR, + }) + + self.assertEqual( + response.status_code, + status.HTTP_403_FORBIDDEN) + + def test_owner_can_t_set_your_role(self): + response, content_data = self.request( + self.repository, + self.owner_token, + self.owner, + { + 'role': RepositoryAuthorization.ROLE_CONTRIBUTOR, + }) + + self.assertEqual( + response.status_code, + status.HTTP_403_FORBIDDEN) From 669108deff51aa4bce11a03af41d44d3d5a3c001 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Thu, 8 Aug 2019 10:55:07 -0300 Subject: [PATCH 104/207] [fix] Test Repository Authorization --- bothub/api/v2/repository/views.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bothub/api/v2/repository/views.py b/bothub/api/v2/repository/views.py index dea99ff7..d4937fe6 100644 --- a/bothub/api/v2/repository/views.py +++ b/bothub/api/v2/repository/views.py @@ -239,7 +239,7 @@ class RepositoryAuthorizationViewSet( IsAuthenticated, ] - def get_object_update(self): + def get_object(self): repository_uuid = self.kwargs.get('repository__uuid') user_nickname = self.kwargs.get('user__nickname') @@ -261,7 +261,7 @@ def update(self, *args, **kwargs): RepositoryAdminManagerAuthorization, ] response = super().update(*args, **kwargs) - instance = self.get_object_update() + instance = self.get_object() if instance.role is not RepositoryAuthorization.ROLE_NOT_SETTED: instance.send_new_role_email(self.request.user) return response From 7277f5ce42195fe41a53b1ef2a79004412c89b35 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Thu, 8 Aug 2019 11:21:06 -0300 Subject: [PATCH 105/207] Refact RequestAuthorization --- bothub/api/v1/views.py | 12 +++ bothub/api/v2/repository/filters.py | 27 +++++ bothub/api/v2/repository/serializers.py | 39 ++++++- bothub/api/v2/repository/views.py | 25 +++++ bothub/api/v2/routers.py | 5 + bothub/api/v2/tests/test_repository.py | 132 ++++++++++++++++++++++++ 6 files changed, 239 insertions(+), 1 deletion(-) diff --git a/bothub/api/v1/views.py b/bothub/api/v1/views.py index fc294a57..53f4595d 100644 --- a/bothub/api/v1/views.py +++ b/bothub/api/v1/views.py @@ -1136,6 +1136,12 @@ def list(self, request, *args, **kwargs): return Response(serializer.data) +@method_decorator( + name='create', + decorator=swagger_auto_schema( + deprecated=True, + ) +) class RequestAuthorizationViewSet( mixins.CreateModelMixin, GenericViewSet): @@ -1149,6 +1155,12 @@ class RequestAuthorizationViewSet( ] +@method_decorator( + name='list', + decorator=swagger_auto_schema( + deprecated=True, + ) +) class RepositoryAuthorizationRequestsViewSet( mixins.ListModelMixin, GenericViewSet): diff --git a/bothub/api/v2/repository/filters.py b/bothub/api/v2/repository/filters.py index 709f801e..0f9180f3 100644 --- a/bothub/api/v2/repository/filters.py +++ b/bothub/api/v2/repository/filters.py @@ -6,6 +6,7 @@ from bothub.common.models import Repository from bothub.common.models import RepositoryAuthorization +from bothub.common.models import RequestRepositoryAuthorization class RepositoriesFilter(filters.FilterSet): @@ -48,3 +49,29 @@ def filter_repository_uuid(self, queryset, name, value): _('Repository {} does not exist').format(value)) except DjangoValidationError: raise NotFound(_('Invalid repository UUID')) + + +class RepositoryAuthorizationRequestsFilter(filters.FilterSet): + class Meta: + model = RequestRepositoryAuthorization + fields = ['repository_uuid'] + + repository_uuid = filters.CharFilter( + field_name='repository_uuid', + required=True, + method='filter_repository_uuid', + help_text=_('Repository\'s UUID')) + + def filter_repository_uuid(self, queryset, name, value): + request = self.request + try: + repository = Repository.objects.get(uuid=value) + authorization = repository.get_user_authorization(request.user) + if not authorization.is_admin: + raise PermissionDenied() + return queryset.filter(repository=repository) + except Repository.DoesNotExist: + raise NotFound( + _('Repository {} does not exist').format(value)) + except DjangoValidationError: + raise NotFound(_('Invalid repository UUID')) diff --git a/bothub/api/v2/repository/serializers.py b/bothub/api/v2/repository/serializers.py index 7309b510..a847c8e6 100644 --- a/bothub/api/v2/repository/serializers.py +++ b/bothub/api/v2/repository/serializers.py @@ -2,6 +2,7 @@ from rest_framework import serializers from rest_framework.exceptions import PermissionDenied +from bothub.api.v2.fields import TextField from bothub.common.models import Repository from bothub.common.models import RepositoryVote from bothub.common.models import RepositoryCategory @@ -9,7 +10,42 @@ from bothub.common.models import RepositoryAuthorization from bothub.common.models import RequestRepositoryAuthorization from bothub.common.languages import LANGUAGE_CHOICES -from ..request.serializers import RequestRepositoryAuthorizationSerializer + + +class RequestRepositoryAuthorizationSerializer(serializers.ModelSerializer): + class Meta: + model = RequestRepositoryAuthorization + fields = [ + 'id', + 'user', + 'user__nickname', + 'repository', + 'text', + 'approved_by', + 'approved_by__nickname', + 'created_at', + ] + ref_name = None + + repository = serializers.PrimaryKeyRelatedField( + queryset=Repository.objects, + style={'show': False}) + user = serializers.HiddenField( + default=serializers.CurrentUserDefault(), + style={'show': False}) + text = TextField( + label=_('Leave a message for repository administrators'), + min_length=5, + max_length=RequestRepositoryAuthorization._meta.get_field( + 'text').max_length) + user__nickname = serializers.SlugRelatedField( + source='user', + slug_field='nickname', + read_only=True) + approved_by__nickname = serializers.SlugRelatedField( + source='approved_by', + slug_field='nickname', + read_only=True) class RepositoryCategorySerializer(serializers.ModelSerializer): @@ -344,3 +380,4 @@ def validate(self, data): if self.instance.user == self.instance.repository.owner: raise PermissionDenied(_('The owner role can\'t be changed.')) return data + diff --git a/bothub/api/v2/repository/views.py b/bothub/api/v2/repository/views.py index d4937fe6..cd16842c 100644 --- a/bothub/api/v2/repository/views.py +++ b/bothub/api/v2/repository/views.py @@ -16,6 +16,7 @@ from bothub.common.models import RepositoryVote from bothub.common.models import RepositoryAuthorization from bothub.common.models import RepositoryCategory +from bothub.common.models import RequestRepositoryAuthorization from ..metadata import Metadata from .serializers import RepositorySerializer, \ @@ -25,10 +26,12 @@ from .serializers import ShortRepositorySerializer from .serializers import RepositoryCategorySerializer from .serializers import RepositoryAuthorizationSerializer +from .serializers import RequestRepositoryAuthorizationSerializer from .permissions import RepositoryPermission from .permissions import RepositoryAdminManagerAuthorization from .filters import RepositoriesFilter from .filters import RepositoryAuthorizationFilter +from .filters import RepositoryAuthorizationRequestsFilter class RepositoryViewSet( @@ -269,3 +272,25 @@ def update(self, *args, **kwargs): def list(self, request, *args, **kwargs): self.lookup_fields = [] return super().list(request, *args, **kwargs) + + +class RepositoryAuthorizationRequestsViewSet( + mixins.ListModelMixin, + mixins.CreateModelMixin, + GenericViewSet): + """ + List of all authorization requests for a repository + """ + queryset = RequestRepositoryAuthorization.objects.exclude( + approved_by__isnull=False) + serializer_class = RequestRepositoryAuthorizationSerializer + filter_class = RepositoryAuthorizationRequestsFilter + permission_classes = [ + IsAuthenticated, + ] + + def create(self, request, *args, **kwargs): + self.queryset = RequestRepositoryAuthorization.objects + self.filter_class = None + return super().create(request, *args, **kwargs) + diff --git a/bothub/api/v2/routers.py b/bothub/api/v2/routers.py index 6a09c944..f388d025 100644 --- a/bothub/api/v2/routers.py +++ b/bothub/api/v2/routers.py @@ -7,6 +7,7 @@ from .repository.views import RepositoryCategoriesView from .repository.views import SearchRepositoriesViewSet from .repository.views import RepositoryAuthorizationViewSet +from .repository.views import RepositoryAuthorizationRequestsViewSet from .examples.views import ExamplesViewSet from .evaluate.views import EvaluateViewSet from .evaluate.views import ResultsListViewSet @@ -100,6 +101,10 @@ def get_lookup_regex(self, viewset, lookup_prefix=''): router.register('repository/examples', ExamplesViewSet) router.register('repository/search-repositories', SearchRepositoriesViewSet) router.register('repository/authorizations', RepositoryAuthorizationViewSet) +router.register( + 'repository/authorization-requests', + RepositoryAuthorizationRequestsViewSet +) router.register('evaluate/results', ResultsListViewSet) router.register('evaluate', EvaluateViewSet) router.register('account/login', LoginViewSet) diff --git a/bothub/api/v2/tests/test_repository.py b/bothub/api/v2/tests/test_repository.py index 89169682..18312bbb 100644 --- a/bothub/api/v2/tests/test_repository.py +++ b/bothub/api/v2/tests/test_repository.py @@ -24,6 +24,8 @@ from bothub.api.v2.repository.views import RepositoryCategoriesView from bothub.api.v2.repository.views import SearchRepositoriesViewSet from bothub.api.v2.repository.views import RepositoryAuthorizationViewSet +from bothub.api.v2.repository.views import \ + RepositoryAuthorizationRequestsViewSet from bothub.api.v2.repository.serializers import RepositorySerializer @@ -1090,3 +1092,133 @@ def test_owner_can_t_set_your_role(self): self.assertEqual( response.status_code, status.HTTP_403_FORBIDDEN) + + +class RepositoryAuthorizationRequestsTestCase(TestCase): + def setUp(self): + self.factory = RequestFactory() + + self.owner, self.owner_token = create_user_and_token('owner') + self.admin, self.admin_token = create_user_and_token('admin') + self.user, self.user_token = create_user_and_token() + + self.repository = Repository.objects.create( + owner=self.owner, + name='Testing', + slug='test', + language=languages.LANGUAGE_EN) + + RequestRepositoryAuthorization.objects.create( + user=self.user, + repository=self.repository, + text='I can contribute') + + admin_autho = self.repository.get_user_authorization(self.admin) + admin_autho.role = RepositoryAuthorization.ROLE_ADMIN + admin_autho.save() + + def request(self, data, token=None): + authorization_header = { + 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), + } if token else {} + request = self.factory.get( + '/v2/repository/authorization-requests/', + data, + **authorization_header) + response = RepositoryAuthorizationRequestsViewSet.as_view( + {'get': 'list'})(request) + response.render() + content_data = json.loads(response.content) + return (response, content_data,) + + def test_okay(self): + response, content_data = self.request({ + 'repository_uuid': self.repository.uuid, + }, self.owner_token) + self.assertEqual( + response.status_code, + status.HTTP_200_OK) + self.assertEqual( + content_data.get('count'), + 1) + + def test_admin_okay(self): + response, content_data = self.request({ + 'repository_uuid': self.repository.uuid, + }, self.admin_token) + self.assertEqual( + response.status_code, + status.HTTP_200_OK) + self.assertEqual( + content_data.get('count'), + 1) + + def test_repository_uuid_empty(self): + response, content_data = self.request({}, self.owner_token) + self.assertEqual( + response.status_code, + status.HTTP_400_BAD_REQUEST) + self.assertEqual( + len(content_data.get('repository_uuid')), + 1) + + def test_forbidden(self): + response, content_data = self.request({ + 'repository_uuid': self.repository.uuid, + }, self.user_token) + self.assertEqual( + response.status_code, + status.HTTP_403_FORBIDDEN) + + +class RequestAuthorizationTestCase(TestCase): + def setUp(self): + self.factory = RequestFactory() + + self.owner, self.owner_token = create_user_and_token('owner') + self.user, self.token = create_user_and_token() + + self.repository = Repository.objects.create( + owner=self.owner, + name='Testing', + slug='test', + language=languages.LANGUAGE_EN) + + def request(self, data, token=None): + authorization_header = { + 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), + } if token else {} + request = self.factory.post( + '/v2/repository/authorization-requests/', + data, + **authorization_header) + response = RepositoryAuthorizationRequestsViewSet.as_view( + {'post': 'create'})(request) + response.render() + content_data = json.loads(response.content) + return (response, content_data,) + + def test_okay(self): + response, content_data = self.request({ + 'repository': self.repository.uuid, + 'text': 'I can contribute', + }, self.token) + self.assertEqual( + response.status_code, + status.HTTP_201_CREATED) + + def test_forbidden_two_requests(self): + RequestRepositoryAuthorization.objects.create( + user=self.user, + repository=self.repository, + text='I can contribute') + response, content_data = self.request({ + 'repository': self.repository.uuid, + 'text': 'I can contribute', + }, self.token) + self.assertEqual( + response.status_code, + status.HTTP_400_BAD_REQUEST) + self.assertIn( + 'non_field_errors', + content_data.keys()) From 0d08a7ea2d187e9781c3dd950681781fc178a331 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Thu, 8 Aug 2019 11:46:15 -0300 Subject: [PATCH 106/207] Refact RequestAuth destroy and update --- bothub/api/v2/repository/serializers.py | 15 +++- bothub/api/v2/repository/views.py | 19 +++++ bothub/api/v2/tests/test_repository.py | 109 ++++++++++++++++++++++++ 3 files changed, 140 insertions(+), 3 deletions(-) diff --git a/bothub/api/v2/repository/serializers.py b/bothub/api/v2/repository/serializers.py index a847c8e6..05cacaf7 100644 --- a/bothub/api/v2/repository/serializers.py +++ b/bothub/api/v2/repository/serializers.py @@ -29,7 +29,8 @@ class Meta: repository = serializers.PrimaryKeyRelatedField( queryset=Repository.objects, - style={'show': False}) + style={'show': False}, + required=False) user = serializers.HiddenField( default=serializers.CurrentUserDefault(), style={'show': False}) @@ -37,7 +38,7 @@ class Meta: label=_('Leave a message for repository administrators'), min_length=5, max_length=RequestRepositoryAuthorization._meta.get_field( - 'text').max_length) + 'text').max_length, required=False) user__nickname = serializers.SlugRelatedField( source='user', slug_field='nickname', @@ -46,6 +47,15 @@ class Meta: source='approved_by', slug_field='nickname', read_only=True) + approved_by = serializers.PrimaryKeyRelatedField( + read_only=True, + style={'show': False}) + + def update(self, instance, validated_data): + validated_data.update({ + 'approved_by': self.context['request'].user, + }) + return super().update(instance, validated_data) class RepositoryCategorySerializer(serializers.ModelSerializer): @@ -380,4 +390,3 @@ def validate(self, data): if self.instance.user == self.instance.repository.owner: raise PermissionDenied(_('The owner role can\'t be changed.')) return data - diff --git a/bothub/api/v2/repository/views.py b/bothub/api/v2/repository/views.py index cd16842c..e01fe26b 100644 --- a/bothub/api/v2/repository/views.py +++ b/bothub/api/v2/repository/views.py @@ -277,6 +277,8 @@ def list(self, request, *args, **kwargs): class RepositoryAuthorizationRequestsViewSet( mixins.ListModelMixin, mixins.CreateModelMixin, + mixins.UpdateModelMixin, + mixins.DestroyModelMixin, GenericViewSet): """ List of all authorization requests for a repository @@ -294,3 +296,20 @@ def create(self, request, *args, **kwargs): self.filter_class = None return super().create(request, *args, **kwargs) + def update(self, request, *args, **kwargs): + self.queryset = RequestRepositoryAuthorization.objects + self.filter_class = None + self.permission_classes = [ + IsAuthenticated, + RepositoryAdminManagerAuthorization, + ] + return super().update(request, *args, **kwargs) + + def destroy(self, request, *args, **kwargs): + self.queryset = RequestRepositoryAuthorization.objects + self.filter_class = None + self.permission_classes = [ + IsAuthenticated, + RepositoryAdminManagerAuthorization, + ] + return super().destroy(request, *args, **kwargs) diff --git a/bothub/api/v2/tests/test_repository.py b/bothub/api/v2/tests/test_repository.py index 18312bbb..506e599b 100644 --- a/bothub/api/v2/tests/test_repository.py +++ b/bothub/api/v2/tests/test_repository.py @@ -1222,3 +1222,112 @@ def test_forbidden_two_requests(self): self.assertIn( 'non_field_errors', content_data.keys()) + + +class ReviewAuthorizationRequestTestCase(TestCase): + def setUp(self): + self.factory = RequestFactory() + + self.owner, self.owner_token = create_user_and_token('owner') + self.admin, self.admin_token = create_user_and_token('admin') + self.user, self.user_token = create_user_and_token() + + repository = Repository.objects.create( + owner=self.owner, + name='Testing', + slug='test', + language=languages.LANGUAGE_EN) + + self.ra = RequestRepositoryAuthorization.objects.create( + user=self.user, + repository=repository, + text='I can contribute') + + admin_autho = repository.get_user_authorization(self.admin) + admin_autho.role = RepositoryAuthorization.ROLE_ADMIN + admin_autho.save() + + def request_approve(self, ra, token=None): + authorization_header = { + 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), + } if token else {} + request = self.factory.put( + '/v2/repository/authorization-requests/{}/'.format(ra.pk), + self.factory._encode_data({}, MULTIPART_CONTENT), + MULTIPART_CONTENT, + **authorization_header) + response = RepositoryAuthorizationRequestsViewSet.as_view( + {'put': 'update'})(request, pk=ra.pk) + response.render() + content_data = json.loads(response.content) + return (response, content_data,) + + def request_reject(self, ra, token=None): + authorization_header = { + 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), + } if token else {} + request = self.factory.delete( + '/v2/repository/authorization-requests/{}/'.format(ra.pk), + **authorization_header) + response = RepositoryAuthorizationRequestsViewSet.as_view( + {'delete': 'destroy'})(request, pk=ra.pk) + response.render() + return response + + def test_approve_okay(self): + response, content_data = self.request_approve( + self.ra, + self.owner_token) + self.assertEqual( + response.status_code, + status.HTTP_200_OK) + self.assertEqual( + content_data.get('approved_by'), + self.owner.id) + + def test_admin_approve_okay(self): + response, content_data = self.request_approve( + self.ra, + self.admin_token) + self.assertEqual( + response.status_code, + status.HTTP_200_OK) + self.assertEqual( + content_data.get('approved_by'), + self.admin.id) + + def test_approve_twice(self): + self.ra.approved_by = self.owner + self.ra.save() + response, content_data = self.request_approve( + self.ra, + self.owner_token) + self.assertEqual( + response.status_code, + status.HTTP_400_BAD_REQUEST) + + def test_approve_forbidden(self): + response, content_data = self.request_approve( + self.ra, + self.user_token) + self.assertEqual( + response.status_code, + status.HTTP_403_FORBIDDEN) + + def test_reject_okay(self): + response = self.request_reject(self.ra, self.owner_token) + self.assertEqual( + response.status_code, + status.HTTP_204_NO_CONTENT) + + def test_admin_reject_okay(self): + response = self.request_reject(self.ra, self.admin_token) + self.assertEqual( + response.status_code, + status.HTTP_204_NO_CONTENT) + + def test_reject_forbidden(self): + response = self.request_reject(self.ra, self.user_token) + self.assertEqual( + response.status_code, + status.HTTP_403_FORBIDDEN) From 318270aa1446eeb346eed69c2138a698cbb6e889 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Thu, 8 Aug 2019 11:59:32 -0300 Subject: [PATCH 107/207] [fix] Test RequestAuth Update --- bothub/api/v1/views.py | 18 ++++++++++++++++++ bothub/api/v2/repository/views.py | 7 ++++++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/bothub/api/v1/views.py b/bothub/api/v1/views.py index 53f4595d..8b89b608 100644 --- a/bothub/api/v1/views.py +++ b/bothub/api/v1/views.py @@ -1176,6 +1176,24 @@ class RepositoryAuthorizationRequestsViewSet( ] +@method_decorator( + name='update', + decorator=swagger_auto_schema( + deprecated=True, + ) +) +@method_decorator( + name='destroy', + decorator=swagger_auto_schema( + deprecated=True, + ) +) +@method_decorator( + name='partial_update', + decorator=swagger_auto_schema( + deprecated=True, + ) +) class ReviewAuthorizationRequestViewSet( mixins.UpdateModelMixin, mixins.DestroyModelMixin, diff --git a/bothub/api/v2/repository/views.py b/bothub/api/v2/repository/views.py index e01fe26b..278bd22d 100644 --- a/bothub/api/v2/repository/views.py +++ b/bothub/api/v2/repository/views.py @@ -1,8 +1,10 @@ from django.utils.decorators import method_decorator from django_filters.rest_framework import DjangoFilterBackend from django.shortcuts import get_object_or_404 +from django.core.exceptions import ValidationError as DjangoValidationError from drf_yasg import openapi from drf_yasg.utils import swagger_auto_schema +from rest_framework.exceptions import ValidationError from rest_framework.response import Response from rest_framework.viewsets import GenericViewSet from rest_framework import mixins, status @@ -303,7 +305,10 @@ def update(self, request, *args, **kwargs): IsAuthenticated, RepositoryAdminManagerAuthorization, ] - return super().update(request, *args, **kwargs) + try: + return super().update(request, *args, **kwargs) + except DjangoValidationError as e: + raise ValidationError(e.message) def destroy(self, request, *args, **kwargs): self.queryset = RequestRepositoryAuthorization.objects From cfc4e6eb6f8f72748004c82ddfa560aba347b2b6 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Thu, 8 Aug 2019 14:16:14 -0300 Subject: [PATCH 108/207] [fix] Test RequestAuth Update --- bothub/api/v2/request/__init__.py | 0 bothub/api/v2/request/serializers.py | 28 ---------------------------- 2 files changed, 28 deletions(-) delete mode 100644 bothub/api/v2/request/__init__.py delete mode 100644 bothub/api/v2/request/serializers.py diff --git a/bothub/api/v2/request/__init__.py b/bothub/api/v2/request/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/bothub/api/v2/request/serializers.py b/bothub/api/v2/request/serializers.py deleted file mode 100644 index ea16940b..00000000 --- a/bothub/api/v2/request/serializers.py +++ /dev/null @@ -1,28 +0,0 @@ -from rest_framework import serializers - -from bothub.common.models import RequestRepositoryAuthorization - - -class RequestRepositoryAuthorizationSerializer(serializers.ModelSerializer): - class Meta: - model = RequestRepositoryAuthorization - fields = [ - 'id', - 'user', - 'user__nickname', - 'repository', - 'text', - 'approved_by', - 'approved_by__nickname', - 'created_at', - ] - ref_name = None - - user__nickname = serializers.SlugRelatedField( - source='user', - slug_field='nickname', - read_only=True) - approved_by__nickname = serializers.SlugRelatedField( - source='approved_by', - slug_field='nickname', - read_only=True) From 54455ea4e8a48b1775858300ea58cd7b8e0f2e29 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Thu, 8 Aug 2019 14:19:27 -0300 Subject: [PATCH 109/207] Added pragma no coveralls --- bothub/api/v2/mixins.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bothub/api/v2/mixins.py b/bothub/api/v2/mixins.py index 420659dd..099f7c75 100644 --- a/bothub/api/v2/mixins.py +++ b/bothub/api/v2/mixins.py @@ -8,7 +8,7 @@ class MultipleFieldLookupMixin(object): filtering. """ - def get_object(self): + def get_object(self): # pragma: no cover queryset = self.get_queryset() queryset = self.filter_queryset(queryset) filter = {} From a85dd3a8cedd7a25dbfd59edc3a63618bc3e6f29 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Thu, 8 Aug 2019 15:19:11 -0300 Subject: [PATCH 110/207] Refact Repository Example --- bothub/api/v1/views.py | 24 + bothub/api/v2/example/serializers.py | 42 ++ bothub/api/v2/repository/permissions.py | 9 + bothub/api/v2/repository/serializers.py | 175 +++++++ bothub/api/v2/repository/validators.py | 76 +++ bothub/api/v2/repository/views.py | 50 +- bothub/api/v2/routers.py | 2 + bothub/api/v2/tests/test_repository.py | 590 ++++++++++++++++++++++++ 8 files changed, 965 insertions(+), 3 deletions(-) create mode 100644 bothub/api/v2/repository/validators.py diff --git a/bothub/api/v1/views.py b/bothub/api/v1/views.py index 8b89b608..84339377 100644 --- a/bothub/api/v1/views.py +++ b/bothub/api/v1/views.py @@ -636,6 +636,12 @@ def get_permissions(self): return super().get_permissions() +@method_decorator( + name='create', + decorator=swagger_auto_schema( + deprecated=True, + ) +) class NewRepositoryExampleViewSet( mixins.CreateModelMixin, GenericViewSet): @@ -653,6 +659,24 @@ class NewRepositoryExampleViewSet( deprecated=True, ) ) +@method_decorator( + name='destroy', + decorator=swagger_auto_schema( + deprecated=True, + ) +) +@method_decorator( + name='update', + decorator=swagger_auto_schema( + deprecated=True, + ) +) +@method_decorator( + name='partial_update', + decorator=swagger_auto_schema( + deprecated=True, + ) +) class RepositoryExampleViewSet( mixins.RetrieveModelMixin, mixins.DestroyModelMixin, diff --git a/bothub/api/v2/example/serializers.py b/bothub/api/v2/example/serializers.py index d96c36e8..edb37144 100644 --- a/bothub/api/v2/example/serializers.py +++ b/bothub/api/v2/example/serializers.py @@ -1,6 +1,10 @@ from django.utils.translation import gettext as _ from rest_framework import serializers +from rest_framework.fields import empty +from bothub.api.v2.fields import EntityValueField +from bothub.api.v2.fields import LabelValueField +from bothub.api.v2.repository.validators import EntityNotEqualLabelValidator from bothub.common.models import RepositoryExample from bothub.common.models import RepositoryExampleEntity @@ -35,6 +39,44 @@ def get_label(self, obj): return obj.entity.label.value +class NewRepositoryExampleEntitySerializer(serializers.ModelSerializer): + class Meta: + model = RepositoryExampleEntity + fields = [ + 'repository_example', + 'start', + 'end', + 'entity', + 'label', + ] + ref_name = None + + repository_example = serializers.PrimaryKeyRelatedField( + queryset=RepositoryExample.objects, + required=False) + + entity = EntityValueField() + label = LabelValueField( + allow_blank=True, + required=False) + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.validators.append(EntityNotEqualLabelValidator()) + + def create(self, validated_data): + repository_example = validated_data.pop('repository_example', None) + assert repository_example + label = validated_data.pop('label', empty) + example_entity = self.Meta.model.objects.create( + repository_example=repository_example, + **validated_data) + if label is not empty: + example_entity.entity.set_label(label) + example_entity.entity.save(update_fields=['label']) + return example_entity + + class RepositoryExampleSerializer(serializers.ModelSerializer): class Meta: model = RepositoryExample diff --git a/bothub/api/v2/repository/permissions.py b/bothub/api/v2/repository/permissions.py index f884427e..653f4f57 100644 --- a/bothub/api/v2/repository/permissions.py +++ b/bothub/api/v2/repository/permissions.py @@ -24,3 +24,12 @@ class RepositoryAdminManagerAuthorization(permissions.BasePermission): def has_object_permission(self, request, view, obj): authorization = obj.repository.get_user_authorization(request.user) return authorization.is_admin + + +class RepositoryExamplePermission(permissions.BasePermission): + def has_object_permission(self, request, view, obj): + authorization = obj.repository_update.repository \ + .get_user_authorization(request.user) + if request.method in READ_METHODS: + return authorization.can_read + return authorization.can_contribute diff --git a/bothub/api/v2/repository/serializers.py b/bothub/api/v2/repository/serializers.py index 05cacaf7..36994e61 100644 --- a/bothub/api/v2/repository/serializers.py +++ b/bothub/api/v2/repository/serializers.py @@ -2,14 +2,32 @@ from rest_framework import serializers from rest_framework.exceptions import PermissionDenied +from bothub.api.v2.example.serializers import \ + RepositoryExampleEntitySerializer +from bothub.api.v2.example.serializers import \ + NewRepositoryExampleEntitySerializer from bothub.api.v2.fields import TextField +from bothub.api.v2.fields import EntityText +from bothub.api.v2.repository.validators import \ + CanContributeInRepositoryExampleValidator +from bothub.api.v2.repository.validators import \ + IntentAndSentenceNotExistsValidator +from bothub.api.v2.repository.validators import \ + ExampleWithIntentOrEntityValidator +from bothub.api.v2.repository.validators import \ + CanContributeInRepositoryValidator +from bothub.common import languages from bothub.common.models import Repository from bothub.common.models import RepositoryVote from bothub.common.models import RepositoryCategory from bothub.common.models import RepositoryEntityLabel from bothub.common.models import RepositoryAuthorization from bothub.common.models import RequestRepositoryAuthorization +from bothub.common.models import RepositoryTranslatedExample +from bothub.common.models import RepositoryExample +from bothub.common.models import RepositoryTranslatedExampleEntity from bothub.common.languages import LANGUAGE_CHOICES +from .validators import CanContributeInRepositoryTranslatedExampleValidator class RequestRepositoryAuthorizationSerializer(serializers.ModelSerializer): @@ -390,3 +408,160 @@ def validate(self, data): if self.instance.user == self.instance.repository.owner: raise PermissionDenied(_('The owner role can\'t be changed.')) return data + + +class RepositoryTranslatedExampleEntitySeralizer(serializers.ModelSerializer): + class Meta: + model = RepositoryTranslatedExampleEntity + fields = [ + 'id', + 'repository_translated_example', + 'start', + 'end', + 'entity', + 'created_at', + 'value', + ] + ref_name = None + + repository_translated_example = serializers.PrimaryKeyRelatedField( + queryset=RepositoryTranslatedExample.objects, + validators=[ + CanContributeInRepositoryTranslatedExampleValidator(), + ], + help_text='Example translation ID') + entity = serializers.SerializerMethodField() + value = serializers.SerializerMethodField() + + def get_entity(self, obj): + return obj.entity.value + + def get_value(self, obj): + return obj.value + + +class RepositoryTranslatedExampleSerializer(serializers.ModelSerializer): + class Meta: + model = RepositoryTranslatedExample + fields = [ + 'id', + 'original_example', + 'from_language', + 'language', + 'text', + 'has_valid_entities', + 'entities', + 'created_at', + ] + ref_name = None + + original_example = serializers.PrimaryKeyRelatedField( + queryset=RepositoryExample.objects, + validators=[ + CanContributeInRepositoryExampleValidator(), + ], + help_text=_('Example\'s ID')) + from_language = serializers.SerializerMethodField() + has_valid_entities = serializers.SerializerMethodField() + entities = RepositoryTranslatedExampleEntitySeralizer( + many=True, + read_only=True) + + def get_from_language(self, obj): + return obj.original_example.repository_update.language + + def get_has_valid_entities(self, obj): + return obj.has_valid_entities + + +class RepositoryExampleSerializer(serializers.ModelSerializer): + class Meta: + model = RepositoryExample + fields = [ + 'id', + 'repository_update', + 'deleted_in', + 'text', + 'intent', + 'language', + 'created_at', + 'entities', + 'translations', + ] + read_only_fields = [ + 'repository_update', + 'deleted_in', + ] + ref_name = None + + entities = RepositoryExampleEntitySerializer( + many=True, + read_only=True) + translations = RepositoryTranslatedExampleSerializer( + many=True, + read_only=True) + language = serializers.SerializerMethodField() + + def get_language(self, obj): + return obj.language + + +class NewRepositoryExampleSerializer(serializers.ModelSerializer): + class Meta: + model = RepositoryExample + fields = [ + 'id', + 'repository', + 'repository_update', + 'text', + 'language', + 'intent', + 'entities', + ] + ref_name = None + + id = serializers.PrimaryKeyRelatedField( + read_only=True, + style={'show': False}) + text = EntityText(style={'entities_field': 'entities'}) + repository = serializers.PrimaryKeyRelatedField( + queryset=Repository.objects, + validators=[ + CanContributeInRepositoryValidator(), + ], + write_only=True, + style={'show': False}) + repository_update = serializers.PrimaryKeyRelatedField( + read_only=True, + style={'show': False}) + language = serializers.ChoiceField( + languages.LANGUAGE_CHOICES, + allow_blank=True, + required=False) + entities = NewRepositoryExampleEntitySerializer( + many=True, + style={'text_field': 'text'}) + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.validators.append(ExampleWithIntentOrEntityValidator()) + self.validators.append(IntentAndSentenceNotExistsValidator()) + + def create(self, validated_data): + entities_data = validated_data.pop('entities') + repository = validated_data.pop('repository') + + try: + language = validated_data.pop('language') + except KeyError: + language = None + repository_update = repository.current_update(language or None) + validated_data.update({'repository_update': repository_update}) + example = self.Meta.model.objects.create(**validated_data) + for entity_data in entities_data: + entity_data.update({'repository_example': example.pk}) + entity_serializer = NewRepositoryExampleEntitySerializer( + data=entity_data) + entity_serializer.is_valid(raise_exception=True) + entity_serializer.save() + return example diff --git a/bothub/api/v2/repository/validators.py b/bothub/api/v2/repository/validators.py new file mode 100644 index 00000000..56175af1 --- /dev/null +++ b/bothub/api/v2/repository/validators.py @@ -0,0 +1,76 @@ +from rest_framework.exceptions import PermissionDenied +from django.utils.translation import gettext as _ +from rest_framework.exceptions import ValidationError + +from bothub.common.models import RepositoryExample + + +class CanContributeInRepositoryExampleValidator(object): + def __call__(self, value): + repository = value.repository_update.repository + user_authorization = repository.get_user_authorization( + self.request.user) + if not user_authorization.can_contribute: + raise PermissionDenied( + _('You can\'t contribute in this repository')) + + def set_context(self, serializer): + self.request = serializer.context.get('request') + + +class CanContributeInRepositoryTranslatedExampleValidator(object): + def __call__(self, value): + repository = value.original_example.repository_update.repository + user_authorization = repository.get_user_authorization( + self.request.user) + if not user_authorization.can_contribute: + raise PermissionDenied( + _('You can\'t contribute in this repository')) + + def set_context(self, serializer): + self.request = serializer.context.get('request') + + +class CanContributeInRepositoryValidator(object): + def __call__(self, value): + user_authorization = value.get_user_authorization( + self.request.user) + if not user_authorization.can_contribute: + raise PermissionDenied( + _('You can\'t contribute in this repository')) + + def set_context(self, serializer): + self.request = serializer.context.get('request') + + +class ExampleWithIntentOrEntityValidator(object): + def __call__(self, attrs): + intent = attrs.get('intent') + entities = attrs.get('entities') + + if not intent and not entities: + raise ValidationError(_('Define a intent or one entity')) + + +class IntentAndSentenceNotExistsValidator(object): + def __call__(self, attrs): + repository = attrs.get('repository') + intent = attrs.get('intent') + sentence = attrs.get('text') + + if RepositoryExample.objects.filter( + text=sentence, + intent=intent, + repository_update__repository=repository + ).count(): + raise ValidationError(_('Intention and Sentence already exists')) + + +class EntityNotEqualLabelValidator(object): + def __call__(self, attrs): + entity = attrs.get('entity') + label = attrs.get('label') + + if entity == label: + raise ValidationError({'label': _( + 'Label name can\'t be equal to entity name')}) diff --git a/bothub/api/v2/repository/views.py b/bothub/api/v2/repository/views.py index 278bd22d..bc0739ea 100644 --- a/bothub/api/v2/repository/views.py +++ b/bothub/api/v2/repository/views.py @@ -2,15 +2,19 @@ from django_filters.rest_framework import DjangoFilterBackend from django.shortcuts import get_object_or_404 from django.core.exceptions import ValidationError as DjangoValidationError +from django.utils.translation import gettext as _ from drf_yasg import openapi from drf_yasg.utils import swagger_auto_schema from rest_framework.exceptions import ValidationError from rest_framework.response import Response from rest_framework.viewsets import GenericViewSet -from rest_framework import mixins, status +from rest_framework import mixins +from rest_framework import status +from rest_framework import permissions from rest_framework.permissions import IsAuthenticatedOrReadOnly from rest_framework.permissions import IsAuthenticated from rest_framework.filters import SearchFilter +from rest_framework.exceptions import APIException from bothub.api.v2.mixins import MultipleFieldLookupMixin from bothub.authentication.models import User @@ -19,18 +23,22 @@ from bothub.common.models import RepositoryAuthorization from bothub.common.models import RepositoryCategory from bothub.common.models import RequestRepositoryAuthorization +from bothub.common.models import RepositoryExample from ..metadata import Metadata -from .serializers import RepositorySerializer, \ - RepositoryAuthorizationRoleSerializer +from .serializers import RepositorySerializer +from .serializers import NewRepositoryExampleSerializer +from .serializers import RepositoryAuthorizationRoleSerializer from .serializers import RepositoryContributionsSerializer from .serializers import RepositoryVotesSerializer from .serializers import ShortRepositorySerializer from .serializers import RepositoryCategorySerializer from .serializers import RepositoryAuthorizationSerializer from .serializers import RequestRepositoryAuthorizationSerializer +from .serializers import RepositoryExampleSerializer from .permissions import RepositoryPermission from .permissions import RepositoryAdminManagerAuthorization +from .permissions import RepositoryExamplePermission from .filters import RepositoriesFilter from .filters import RepositoryAuthorizationFilter from .filters import RepositoryAuthorizationRequestsFilter @@ -318,3 +326,39 @@ def destroy(self, request, *args, **kwargs): RepositoryAdminManagerAuthorization, ] return super().destroy(request, *args, **kwargs) + + +class RepositoryExampleViewSet( + mixins.CreateModelMixin, + mixins.RetrieveModelMixin, + mixins.DestroyModelMixin, + mixins.UpdateModelMixin, + GenericViewSet): + """ + Manager repository example. + + retrieve: + Get repository example data. + + delete: + Delete repository example. + + update: + Update repository example. + + """ + queryset = RepositoryExample.objects + serializer_class = RepositoryExampleSerializer + permission_classes = [ + RepositoryExamplePermission, + ] + + def create(self, request, *args, **kwargs): + self.serializer_class = NewRepositoryExampleSerializer + self.permission_classes = [permissions.IsAuthenticated] + return super().create(request, *args, **kwargs) + + def perform_destroy(self, obj): + if obj.deleted_in: + raise APIException(_('Example already deleted')) + obj.delete() diff --git a/bothub/api/v2/routers.py b/bothub/api/v2/routers.py index f388d025..518b0c59 100644 --- a/bothub/api/v2/routers.py +++ b/bothub/api/v2/routers.py @@ -8,6 +8,7 @@ from .repository.views import SearchRepositoriesViewSet from .repository.views import RepositoryAuthorizationViewSet from .repository.views import RepositoryAuthorizationRequestsViewSet +from .repository.views import RepositoryExampleViewSet from .examples.views import ExamplesViewSet from .evaluate.views import EvaluateViewSet from .evaluate.views import ResultsListViewSet @@ -105,6 +106,7 @@ def get_lookup_regex(self, viewset, lookup_prefix=''): 'repository/authorization-requests', RepositoryAuthorizationRequestsViewSet ) +router.register('repository/example', RepositoryExampleViewSet) router.register('evaluate/results', ResultsListViewSet) router.register('evaluate', EvaluateViewSet) router.register('account/login', LoginViewSet) diff --git a/bothub/api/v2/tests/test_repository.py b/bothub/api/v2/tests/test_repository.py index 506e599b..faeba5d5 100644 --- a/bothub/api/v2/tests/test_repository.py +++ b/bothub/api/v2/tests/test_repository.py @@ -13,6 +13,8 @@ from bothub.common.models import RequestRepositoryAuthorization from bothub.common.models import RepositoryExample from bothub.common.models import RepositoryTranslatedExample +from bothub.common.models import RepositoryExampleEntity +from bothub.common.models import RepositoryUpdate from bothub.common import languages from bothub.api.v2.tests.utils import create_user_and_token @@ -26,6 +28,7 @@ from bothub.api.v2.repository.views import RepositoryAuthorizationViewSet from bothub.api.v2.repository.views import \ RepositoryAuthorizationRequestsViewSet +from bothub.api.v2.repository.views import RepositoryExampleViewSet from bothub.api.v2.repository.serializers import RepositorySerializer @@ -1331,3 +1334,590 @@ def test_reject_forbidden(self): self.assertEqual( response.status_code, status.HTTP_403_FORBIDDEN) + + +class RepositoryExampleRetrieveTestCase(TestCase): + def setUp(self): + self.factory = RequestFactory() + + self.owner, self.owner_token = create_user_and_token('owner') + self.user, self.user_token = create_user_and_token() + + self.repository = Repository.objects.create( + owner=self.owner, + name='Testing', + slug='test', + language=languages.LANGUAGE_EN) + self.example = RepositoryExample.objects.create( + repository_update=self.repository.current_update(), + text='my name is douglas') + self.example_entity = RepositoryExampleEntity.objects.create( + repository_example=self.example, + start=11, + end=18, + entity='name') + + self.private_repository = Repository.objects.create( + owner=self.owner, + name='Testing Private', + slug='private', + language=languages.LANGUAGE_EN, + is_private=True) + self.private_example = RepositoryExample.objects.create( + repository_update=self.private_repository.current_update(), + text='hi') + + def request(self, example, token): + authorization_header = { + 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), + } + request = self.factory.get( + '/v2/repository/example/{}/'.format(example.id), + **authorization_header) + response = RepositoryExampleViewSet.as_view( + {'get': 'retrieve'})(request, pk=example.id) + response.render() + content_data = json.loads(response.content) + return (response, content_data,) + + def test_okay(self): + response, content_data = self.request( + self.example, + self.owner_token) + self.assertEqual( + response.status_code, + status.HTTP_200_OK) + self.assertEqual( + content_data.get('id'), + self.example.id) + + def test_forbidden(self): + response, content_data = self.request( + self.private_example, + self.user_token) + self.assertEqual( + response.status_code, + status.HTTP_403_FORBIDDEN) + + def test_public(self): + response, content_data = self.request( + self.example, + self.user_token) + self.assertEqual( + response.status_code, + status.HTTP_200_OK) + self.assertEqual( + content_data.get('id'), + self.example.id) + + def test_list_entities(self): + response, content_data = self.request( + self.example, + self.owner_token) + self.assertEqual( + response.status_code, + status.HTTP_200_OK) + self.assertEqual( + len(content_data.get('entities')), + 1) + + def test_entity_has_label(self): + response, content_data = self.request( + self.example, + self.owner_token) + self.assertEqual( + response.status_code, + status.HTTP_200_OK) + entity = content_data.get('entities')[0] + self.assertIn( + 'label', + entity.keys()) + + def test_entity_has_valid_label(self): + label = 'subject' + self.example_entity.entity.set_label('subject') + self.example_entity.entity.save(update_fields=['label']) + response, content_data = self.request( + self.example, + self.owner_token) + self.assertEqual( + response.status_code, + status.HTTP_200_OK) + entity = content_data.get('entities')[0] + self.assertIn( + 'label', + entity.keys()) + self.assertEqual( + entity.get('label'), + label) + + +class RepositoryExampleDestroyTestCase(TestCase): + def setUp(self): + self.factory = RequestFactory() + + self.owner, self.owner_token = create_user_and_token('owner') + self.user, self.user_token = create_user_and_token() + + self.repository = Repository.objects.create( + owner=self.owner, + name='Testing', + slug='test', + language=languages.LANGUAGE_EN) + self.example = RepositoryExample.objects.create( + repository_update=self.repository.current_update(), + text='hi') + + self.private_repository = Repository.objects.create( + owner=self.owner, + name='Testing Private', + slug='private', + language=languages.LANGUAGE_EN, + is_private=True) + self.private_example = RepositoryExample.objects.create( + repository_update=self.private_repository.current_update(), + text='hi') + + def request(self, example, token): + authorization_header = { + 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), + } + request = self.factory.delete( + '/v2/repository/example/{}/'.format(example.id), + **authorization_header) + response = RepositoryExampleViewSet.as_view( + {'delete': 'destroy'})(request, pk=example.id) + return response + + def test_okay(self): + response = self.request( + self.example, + self.owner_token) + self.assertEqual( + response.status_code, + status.HTTP_204_NO_CONTENT) + + def test_private_okay(self): + response = self.request( + self.private_example, + self.owner_token) + self.assertEqual( + response.status_code, + status.HTTP_204_NO_CONTENT) + + def test_forbidden(self): + response = self.request( + self.example, + self.user_token) + self.assertEqual( + response.status_code, + status.HTTP_403_FORBIDDEN) + + def test_private_forbidden(self): + response = self.request( + self.private_example, + self.user_token) + self.assertEqual( + response.status_code, + status.HTTP_403_FORBIDDEN) + + def test_already_deleted(self): + self.example.delete() + + response = self.request( + self.example, + self.owner_token) + self.assertEqual( + response.status_code, + status.HTTP_500_INTERNAL_SERVER_ERROR) + + +class RepositoryExampleUpdateTestCase(TestCase): + def setUp(self): + self.factory = RequestFactory() + + self.owner, self.owner_token = create_user_and_token('owner') + self.user, self.user_token = create_user_and_token() + + self.repository = Repository.objects.create( + owner=self.owner, + name='Testing', + slug='test', + language=languages.LANGUAGE_EN) + self.example = RepositoryExample.objects.create( + repository_update=self.repository.current_update(), + text='hi') + + self.private_repository = Repository.objects.create( + owner=self.owner, + name='Testing Private', + slug='private', + language=languages.LANGUAGE_EN, + is_private=True) + self.private_example = RepositoryExample.objects.create( + repository_update=self.private_repository.current_update(), + text='hi') + + def request(self, example, token, data): + authorization_header = { + 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), + } + request = self.factory.patch( + '/v2/repository/example/{}/'.format(example.id), + json.dumps(data), + content_type='application/json', + **authorization_header) + response = RepositoryExampleViewSet.as_view( + {'patch': 'update'})(request, pk=example.id) + response.render() + content_data = json.loads(response.content) + return (response, content_data,) + + def test_okay(self): + text = 'teste' + intent = 'teste1234' + + response, content_data = self.request( + self.example, + self.owner_token, + {"text": text, "intent": intent} + ) + + self.assertEqual( + response.status_code, + status.HTTP_200_OK) + self.assertEqual( + content_data.get('text'), + text) + self.assertEqual( + content_data.get('intent'), + intent) + + def test_private_forbidden(self): + response, content_data = self.request( + self.private_example, + self.user_token, + {"text": 'teste', "intent": 'teste1234'}) + + self.assertEqual( + response.status_code, + status.HTTP_403_FORBIDDEN) + + +class NewRepositoryExampleTestCase(TestCase): + def setUp(self): + self.factory = RequestFactory() + + self.owner, self.owner_token = create_user_and_token('owner') + self.user, self.user_token = create_user_and_token() + + self.repository = Repository.objects.create( + owner=self.owner, + name='Testing', + slug='test', + language=languages.LANGUAGE_EN) + + def request(self, token, data): + authorization_header = { + 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), + } + request = self.factory.post( + '/v2/repository/example/', + json.dumps(data), + content_type='application/json', + **authorization_header) + response = RepositoryExampleViewSet.as_view( + {'post': 'create'})(request) + response.render() + content_data = json.loads(response.content) + return (response, content_data,) + + def test_okay(self): + text = 'hi' + intent = 'greet' + response, content_data = self.request( + self.owner_token, + { + 'repository': str(self.repository.uuid), + 'text': text, + 'intent': intent, + 'entities': [], + }) + self.assertEqual( + response.status_code, + status.HTTP_201_CREATED) + self.assertEqual( + content_data.get('text'), + text) + self.assertEqual( + content_data.get('intent'), + intent) + + def test_okay_with_language(self): + text = 'hi' + intent = 'greet' + language = languages.LANGUAGE_PT + response, content_data = self.request( + self.owner_token, + { + 'repository': str(self.repository.uuid), + 'text': text, + 'language': language, + 'intent': intent, + 'entities': [], + }) + self.assertEqual( + response.status_code, + status.HTTP_201_CREATED) + self.assertEqual( + content_data.get('text'), + text) + self.assertEqual( + content_data.get('intent'), + intent) + repository_update_pk = content_data.get('repository_update') + repository_update = RepositoryUpdate.objects.get( + pk=repository_update_pk) + self.assertEqual(repository_update.language, language) + + def test_forbidden(self): + response, content_data = self.request( + self.user_token, + { + 'repository': str(self.repository.uuid), + 'text': 'hi', + 'intent': 'greet', + 'entities': [], + }) + self.assertEqual( + response.status_code, + status.HTTP_403_FORBIDDEN) + + def test_repository_uuid_required(self): + response, content_data = self.request( + self.owner_token, + { + 'text': 'hi', + 'intent': 'greet', + 'entities': [], + }) + self.assertEqual( + response.status_code, + status.HTTP_400_BAD_REQUEST) + + def test_repository_does_not_exists(self): + response, content_data = self.request( + self.owner_token, + { + 'repository': str(uuid.uuid4()), + 'text': 'hi', + 'intent': 'greet', + 'entities': [], + }) + self.assertEqual( + response.status_code, + status.HTTP_400_BAD_REQUEST) + self.assertIn( + 'repository', + content_data.keys()) + + def test_invalid_repository_uuid(self): + response, content_data = self.request( + self.owner_token, + { + 'repository': 'invalid', + 'text': 'hi', + 'intent': 'greet', + 'entities': [], + }) + self.assertEqual( + response.status_code, + status.HTTP_400_BAD_REQUEST) + + def test_with_entities(self): + response, content_data = self.request( + self.owner_token, + { + 'repository': str(self.repository.uuid), + 'text': 'my name is douglas', + 'intent': 'greet', + 'entities': [ + { + 'start': 11, + 'end': 18, + 'entity': 'name', + }, + ], + }) + self.assertEqual( + response.status_code, + status.HTTP_201_CREATED) + self.assertEqual( + len(content_data.get('entities')), + 1) + + def test_exists_example(self): + text = 'hi' + intent = 'greet' + response_created, content_data_created = self.request( + self.owner_token, + { + 'repository': str(self.repository.uuid), + 'text': text, + 'intent': intent, + 'entities': [], + }) + + self.assertEqual( + response_created.status_code, + status.HTTP_201_CREATED) + + response, content_data = self.request( + self.owner_token, + { + 'repository': str(self.repository.uuid), + 'text': text, + 'intent': intent, + 'entities': [], + }) + + self.assertEqual( + content_data.get('non_field_errors')[0], + 'Intention and Sentence already exists' + ) + + self.assertEqual( + response.status_code, + status.HTTP_400_BAD_REQUEST) + + def test_with_entities_with_label(self): + response, content_data = self.request( + self.owner_token, + { + 'repository': str(self.repository.uuid), + 'text': 'my name is douglas', + 'intent': 'greet', + 'entities': [ + { + 'start': 11, + 'end': 18, + 'entity': 'name', + 'label': 'subject', + }, + ], + }) + self.assertEqual( + response.status_code, + status.HTTP_201_CREATED) + self.assertEqual( + len(content_data.get('entities')), + 1) + id = content_data.get('id') + repository_example = RepositoryExample.objects.get(id=id) + example_entity = repository_example.entities.all()[0] + self.assertIsNotNone(example_entity.entity.label) + + def test_with_entities_with_invalid_label(self): + response, content_data = self.request( + self.owner_token, + { + 'repository': str(self.repository.uuid), + 'text': 'my name is douglas', + 'intent': 'greet', + 'entities': [ + { + 'start': 11, + 'end': 18, + 'entity': 'name', + 'label': 'other', + }, + ], + }) + self.assertEqual( + response.status_code, + status.HTTP_400_BAD_REQUEST) + self.assertIn( + 'entities', + content_data.keys()) + entities_errors = content_data.get('entities') + self.assertIn( + 'label', + entities_errors[0]) + + def test_with_entities_with_equal_label(self): + response, content_data = self.request( + self.owner_token, + { + 'repository': str(self.repository.uuid), + 'text': 'my name is douglas', + 'intent': 'greet', + 'entities': [ + { + 'start': 11, + 'end': 18, + 'entity': 'name', + 'label': 'name', + }, + ], + }) + self.assertEqual( + response.status_code, + status.HTTP_400_BAD_REQUEST) + self.assertIn( + 'entities', + content_data.keys()) + entities_errors = content_data.get('entities') + self.assertIn( + 'label', + entities_errors[0]) + + def test_intent_or_entity_required(self): + response, content_data = self.request( + self.owner_token, + { + 'repository': str(self.repository.uuid), + 'text': 'hi', + 'intent': '', + 'entities': [], + }) + self.assertEqual( + response.status_code, + status.HTTP_400_BAD_REQUEST) + + def test_entity_with_special_char(self): + response, content_data = self.request( + self.owner_token, + { + 'repository': str(self.repository.uuid), + 'text': 'my name is douglas', + 'intent': '', + 'entities': [ + { + 'start': 11, + 'end': 18, + 'entity': 'nam&', + }, + ], + }) + self.assertEqual( + response.status_code, + status.HTTP_400_BAD_REQUEST) + self.assertEqual( + len(content_data.get('entities')), + 1) + + def test_intent_with_special_char(self): + response, content_data = self.request( + self.owner_token, + { + 'repository': str(self.repository.uuid), + 'text': 'my name is douglas', + 'intent': 'nam$s', + 'entities': [], + }) + self.assertEqual( + response.status_code, + status.HTTP_400_BAD_REQUEST) + self.assertEqual( + len(content_data.get('intent')), + 1) From 01a08269929a3a6da55a6389c18fac3202e21114 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Fri, 9 Aug 2019 11:24:21 -0300 Subject: [PATCH 111/207] Refact Repository Example Create --- bothub/api/v2/example/serializers.py | 40 +++++++-------------- bothub/api/v2/repository/serializers.py | 46 +++++++------------------ bothub/api/v2/repository/views.py | 2 -- bothub/api/v2/tests/test_repository.py | 12 ++++--- 4 files changed, 33 insertions(+), 67 deletions(-) diff --git a/bothub/api/v2/example/serializers.py b/bothub/api/v2/example/serializers.py index edb37144..23f63ae6 100644 --- a/bothub/api/v2/example/serializers.py +++ b/bothub/api/v2/example/serializers.py @@ -18,7 +18,9 @@ class Meta: 'start', 'end', 'entity', + 'entity_method', 'label', + 'label_method', 'created_at', 'value', ] @@ -26,34 +28,10 @@ class Meta: repository_example = serializers.PrimaryKeyRelatedField( queryset=RepositoryExample.objects, - help_text=_('Example\'s ID')) - entity = serializers.SerializerMethodField() - label = serializers.SerializerMethodField() - - def get_entity(self, obj): - return obj.entity.value - - def get_label(self, obj): - if not obj.entity.label: - return None - return obj.entity.label.value - - -class NewRepositoryExampleEntitySerializer(serializers.ModelSerializer): - class Meta: - model = RepositoryExampleEntity - fields = [ - 'repository_example', - 'start', - 'end', - 'entity', - 'label', - ] - ref_name = None - - repository_example = serializers.PrimaryKeyRelatedField( - queryset=RepositoryExample.objects, + help_text=_('Example\'s ID'), required=False) + entity_method = serializers.SerializerMethodField(required=False) + label_method = serializers.SerializerMethodField(required=False) entity = EntityValueField() label = LabelValueField( @@ -64,6 +42,14 @@ def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.validators.append(EntityNotEqualLabelValidator()) + def get_entity_method(self, obj): + return obj.entity.value + + def get_label_method(self, obj): + if not obj.entity.label: + return None + return obj.entity.label.value + def create(self, validated_data): repository_example = validated_data.pop('repository_example', None) assert repository_example diff --git a/bothub/api/v2/repository/serializers.py b/bothub/api/v2/repository/serializers.py index 36994e61..5174658f 100644 --- a/bothub/api/v2/repository/serializers.py +++ b/bothub/api/v2/repository/serializers.py @@ -4,8 +4,6 @@ from bothub.api.v2.example.serializers import \ RepositoryExampleEntitySerializer -from bothub.api.v2.example.serializers import \ - NewRepositoryExampleEntitySerializer from bothub.api.v2.fields import TextField from bothub.api.v2.fields import EntityText from bothub.api.v2.repository.validators import \ @@ -479,6 +477,7 @@ class Meta: model = RepositoryExample fields = [ 'id', + 'repository', 'repository_update', 'deleted_in', 'text', @@ -489,41 +488,14 @@ class Meta: 'translations', ] read_only_fields = [ - 'repository_update', 'deleted_in', ] ref_name = None - entities = RepositoryExampleEntitySerializer( - many=True, - read_only=True) - translations = RepositoryTranslatedExampleSerializer( - many=True, - read_only=True) - language = serializers.SerializerMethodField() - - def get_language(self, obj): - return obj.language - - -class NewRepositoryExampleSerializer(serializers.ModelSerializer): - class Meta: - model = RepositoryExample - fields = [ - 'id', - 'repository', - 'repository_update', - 'text', - 'language', - 'intent', - 'entities', - ] - ref_name = None - id = serializers.PrimaryKeyRelatedField( read_only=True, style={'show': False}) - text = EntityText(style={'entities_field': 'entities'}) + text = EntityText(style={'entities_field': 'entities'}, required=False) repository = serializers.PrimaryKeyRelatedField( queryset=Repository.objects, validators=[ @@ -533,14 +505,19 @@ class Meta: style={'show': False}) repository_update = serializers.PrimaryKeyRelatedField( read_only=True, - style={'show': False}) + style={'show': False}, required=False) language = serializers.ChoiceField( languages.LANGUAGE_CHOICES, allow_blank=True, required=False) - entities = NewRepositoryExampleEntitySerializer( + + entities = RepositoryExampleEntitySerializer( + many=True, + style={'text_field': 'text'}, + required=False) + translations = RepositoryTranslatedExampleSerializer( many=True, - style={'text_field': 'text'}) + read_only=True) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) @@ -560,8 +537,9 @@ def create(self, validated_data): example = self.Meta.model.objects.create(**validated_data) for entity_data in entities_data: entity_data.update({'repository_example': example.pk}) - entity_serializer = NewRepositoryExampleEntitySerializer( + entity_serializer = RepositoryExampleEntitySerializer( data=entity_data) entity_serializer.is_valid(raise_exception=True) entity_serializer.save() return example + diff --git a/bothub/api/v2/repository/views.py b/bothub/api/v2/repository/views.py index bc0739ea..c1df7915 100644 --- a/bothub/api/v2/repository/views.py +++ b/bothub/api/v2/repository/views.py @@ -27,7 +27,6 @@ from ..metadata import Metadata from .serializers import RepositorySerializer -from .serializers import NewRepositoryExampleSerializer from .serializers import RepositoryAuthorizationRoleSerializer from .serializers import RepositoryContributionsSerializer from .serializers import RepositoryVotesSerializer @@ -354,7 +353,6 @@ class RepositoryExampleViewSet( ] def create(self, request, *args, **kwargs): - self.serializer_class = NewRepositoryExampleSerializer self.permission_classes = [permissions.IsAuthenticated] return super().create(request, *args, **kwargs) diff --git a/bothub/api/v2/tests/test_repository.py b/bothub/api/v2/tests/test_repository.py index faeba5d5..51fa90c4 100644 --- a/bothub/api/v2/tests/test_repository.py +++ b/bothub/api/v2/tests/test_repository.py @@ -1430,7 +1430,7 @@ def test_entity_has_label(self): status.HTTP_200_OK) entity = content_data.get('entities')[0] self.assertIn( - 'label', + 'label_method', entity.keys()) def test_entity_has_valid_label(self): @@ -1445,10 +1445,10 @@ def test_entity_has_valid_label(self): status.HTTP_200_OK) entity = content_data.get('entities')[0] self.assertIn( - 'label', + 'label_method', entity.keys()) self.assertEqual( - entity.get('label'), + entity.get('label_method'), label) @@ -1580,7 +1580,11 @@ def test_okay(self): response, content_data = self.request( self.example, self.owner_token, - {"text": text, "intent": intent} + { + "repository": str(self.repository.uuid), + "text": text, + "intent": intent + } ) self.assertEqual( From 5ef620e628147a3b1350e49ea3cd100187b78786 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Fri, 9 Aug 2019 11:25:38 -0300 Subject: [PATCH 112/207] PEP8 --- bothub/api/v2/repository/serializers.py | 1 - 1 file changed, 1 deletion(-) diff --git a/bothub/api/v2/repository/serializers.py b/bothub/api/v2/repository/serializers.py index 5174658f..1de40de4 100644 --- a/bothub/api/v2/repository/serializers.py +++ b/bothub/api/v2/repository/serializers.py @@ -542,4 +542,3 @@ def create(self, validated_data): entity_serializer.is_valid(raise_exception=True) entity_serializer.save() return example - From 828a0b31f9ed1a62e85105e5236addd6d4b2d507 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Mon, 12 Aug 2019 17:08:11 -0300 Subject: [PATCH 113/207] Refact Repository Example --- bothub/api/v2/example/serializers.py | 13 +++++-------- bothub/api/v2/repository/serializers.py | 7 +++++++ bothub/api/v2/tests/test_repository.py | 6 +++--- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/bothub/api/v2/example/serializers.py b/bothub/api/v2/example/serializers.py index 23f63ae6..84bcab4d 100644 --- a/bothub/api/v2/example/serializers.py +++ b/bothub/api/v2/example/serializers.py @@ -18,9 +18,7 @@ class Meta: 'start', 'end', 'entity', - 'entity_method', 'label', - 'label_method', 'created_at', 'value', ] @@ -30,8 +28,6 @@ class Meta: queryset=RepositoryExample.objects, help_text=_('Example\'s ID'), required=False) - entity_method = serializers.SerializerMethodField(required=False) - label_method = serializers.SerializerMethodField(required=False) entity = EntityValueField() label = LabelValueField( @@ -40,12 +36,13 @@ class Meta: def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) + if kwargs.get('data') == 'GET': + self.fields['label'] = serializers.SerializerMethodField( + required=False + ) self.validators.append(EntityNotEqualLabelValidator()) - def get_entity_method(self, obj): - return obj.entity.value - - def get_label_method(self, obj): + def get_label(self, obj): if not obj.entity.label: return None return obj.entity.label.value diff --git a/bothub/api/v2/repository/serializers.py b/bothub/api/v2/repository/serializers.py index 1de40de4..2e4a2f0e 100644 --- a/bothub/api/v2/repository/serializers.py +++ b/bothub/api/v2/repository/serializers.py @@ -521,6 +521,13 @@ class Meta: def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) + if kwargs['context'].get('request').stream is None: + self.fields['entities'] = \ + RepositoryExampleEntitySerializer( + many=True, + style={'text_field': 'text'}, + data='GET' + ) self.validators.append(ExampleWithIntentOrEntityValidator()) self.validators.append(IntentAndSentenceNotExistsValidator()) diff --git a/bothub/api/v2/tests/test_repository.py b/bothub/api/v2/tests/test_repository.py index 51fa90c4..0a5ccbcb 100644 --- a/bothub/api/v2/tests/test_repository.py +++ b/bothub/api/v2/tests/test_repository.py @@ -1430,7 +1430,7 @@ def test_entity_has_label(self): status.HTTP_200_OK) entity = content_data.get('entities')[0] self.assertIn( - 'label_method', + 'label', entity.keys()) def test_entity_has_valid_label(self): @@ -1445,10 +1445,10 @@ def test_entity_has_valid_label(self): status.HTTP_200_OK) entity = content_data.get('entities')[0] self.assertIn( - 'label_method', + 'label', entity.keys()) self.assertEqual( - entity.get('label_method'), + entity.get('label'), label) From 8ec803e0ea83799357aece0023073f03826d1552 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Tue, 13 Aug 2019 10:00:12 -0300 Subject: [PATCH 114/207] Migrate Translation v1 to v2 and Refact --- bothub/api/v1/views.py | 36 ++ bothub/api/v2/routers.py | 2 + bothub/api/v2/tests/test_translation.py | 495 +++++++++++++++++++++++ bothub/api/v2/translation/__init__.py | 0 bothub/api/v2/translation/filters.py | 50 +++ bothub/api/v2/translation/permissions.py | 12 + bothub/api/v2/translation/serializers.py | 112 +++++ bothub/api/v2/translation/validators.py | 63 +++ bothub/api/v2/translation/views.py | 52 +++ 9 files changed, 822 insertions(+) create mode 100644 bothub/api/v2/tests/test_translation.py create mode 100644 bothub/api/v2/translation/__init__.py create mode 100644 bothub/api/v2/translation/filters.py create mode 100644 bothub/api/v2/translation/permissions.py create mode 100644 bothub/api/v2/translation/serializers.py create mode 100644 bothub/api/v2/translation/validators.py create mode 100644 bothub/api/v2/translation/views.py diff --git a/bothub/api/v1/views.py b/bothub/api/v1/views.py index 84339377..a1431304 100644 --- a/bothub/api/v1/views.py +++ b/bothub/api/v1/views.py @@ -707,6 +707,12 @@ def perform_destroy(self, obj): obj.delete() +@method_decorator( + name='create', + decorator=swagger_auto_schema( + deprecated=True, + ) +) class NewRepositoryTranslatedExampleViewSet( mixins.CreateModelMixin, GenericViewSet): @@ -718,6 +724,30 @@ class NewRepositoryTranslatedExampleViewSet( permission_classes = [permissions.IsAuthenticated] +@method_decorator( + name='retrieve', + decorator=swagger_auto_schema( + deprecated=True, + ) +) +@method_decorator( + name='update', + decorator=swagger_auto_schema( + deprecated=True, + ) +) +@method_decorator( + name='partial_update', + decorator=swagger_auto_schema( + deprecated=True, + ) +) +@method_decorator( + name='destroy', + decorator=swagger_auto_schema( + deprecated=True, + ) +) class RepositoryTranslatedExampleViewSet( mixins.RetrieveModelMixin, mixins.UpdateModelMixin, @@ -1020,6 +1050,12 @@ class RepositoriesViewSet( ] +@method_decorator( + name='list', + decorator=swagger_auto_schema( + deprecated=True, + ) +) class TranslationsViewSet( mixins.ListModelMixin, GenericViewSet): diff --git a/bothub/api/v2/routers.py b/bothub/api/v2/routers.py index 518b0c59..6b40fd6c 100644 --- a/bothub/api/v2/routers.py +++ b/bothub/api/v2/routers.py @@ -19,6 +19,7 @@ from .account.views import UserProfileViewSet from .account.views import SearchUserViewSet from .account.views import ResetPasswordViewSet +from .translation.views import RepositoryTranslatedExampleViewSet class Router(routers.SimpleRouter): @@ -116,3 +117,4 @@ def get_lookup_regex(self, viewset, lookup_prefix=''): router.register('account/user-profile', UserProfileViewSet) router.register('account/search-user', SearchUserViewSet) router.register('account/reset-password', ResetPasswordViewSet) +router.register('translation', RepositoryTranslatedExampleViewSet) diff --git a/bothub/api/v2/tests/test_translation.py b/bothub/api/v2/tests/test_translation.py new file mode 100644 index 00000000..c8be286c --- /dev/null +++ b/bothub/api/v2/tests/test_translation.py @@ -0,0 +1,495 @@ +import json +import uuid + +from django.test import TestCase +from django.test import RequestFactory +from rest_framework import status + +from bothub.common import languages +from bothub.common.models import Repository, RepositoryExampleEntity +from bothub.common.models import RepositoryExample +from bothub.common.models import RepositoryTranslatedExample + +from bothub.api.v2.translation.views import \ + RepositoryTranslatedExampleViewSet + +from .utils import create_user_and_token + + +class TranslateExampleTestCase(TestCase): + def setUp(self): + self.factory = RequestFactory() + + self.owner, self.owner_token = create_user_and_token('owner') + + self.repository = Repository.objects.create( + owner=self.owner, + name='Testing', + slug='test', + language=languages.LANGUAGE_EN) + self.example = RepositoryExample.objects.create( + repository_update=self.repository.current_update(), + text='hi') + + def request(self, data, user_token): + authorization_header = { + 'HTTP_AUTHORIZATION': 'Token {}'.format(user_token.key), + } + request = self.factory.post( + '/v2/translation/', + json.dumps(data), + content_type='application/json', + **authorization_header) + response = RepositoryTranslatedExampleViewSet.as_view( + {'post': 'create'})(request) + response.render() + content_data = json.loads(response.content) + return (response, content_data,) + + def test_okay(self): + response, content_data = self.request( + { + 'original_example': self.example.id, + 'language': languages.LANGUAGE_PT, + 'text': 'oi', + 'entities': [], + }, + self.owner_token) + self.assertEqual( + response.status_code, + status.HTTP_201_CREATED) + + def test_unique_translate(self): + language = languages.LANGUAGE_PT + text = 'oi' + + RepositoryTranslatedExample.objects.create( + original_example=self.example, + language=language, + text=text) + + response, content_data = self.request( + { + 'original_example': self.example.id, + 'language': language, + 'text': text, + 'entities': [], + }, + self.owner_token) + self.assertEqual( + response.status_code, + status.HTTP_400_BAD_REQUEST) + self.assertIn( + 'non_field_errors', + content_data.keys()) + + def test_forbidden(self): + user, user_token = create_user_and_token() + + response, content_data = self.request( + { + 'original_example': self.example.id, + 'language': languages.LANGUAGE_PT, + 'text': 'oi', + 'entities': [], + }, + user_token) + self.assertEqual( + response.status_code, + status.HTTP_403_FORBIDDEN) + + def test_okay_with_entities(self): + example = RepositoryExample.objects.create( + repository_update=self.repository.current_update(), + text='my name is douglas') + RepositoryExampleEntity.objects.create( + repository_example=example, + start=11, + end=18, + entity='name') + response, content_data = self.request( + { + 'original_example': example.id, + 'language': languages.LANGUAGE_PT, + 'text': 'meu nome é douglas', + 'entities': [ + { + 'start': 11, + 'end': 18, + 'entity': 'name', + }, + ], + }, + self.owner_token) + self.assertEqual( + response.status_code, + status.HTTP_201_CREATED) + self.assertEqual( + len(content_data.get('entities')), + 1) + + def test_entities_no_valid(self): + example = RepositoryExample.objects.create( + repository_update=self.repository.current_update(), + text='my name is douglas') + RepositoryExampleEntity.objects.create( + repository_example=self.example, + start=11, + end=18, + entity='name') + response, content_data = self.request( + { + 'original_example': example.id, + 'language': languages.LANGUAGE_PT, + 'text': 'meu nome é douglas', + 'entities': [ + { + 'start': 11, + 'end': 18, + 'entity': 'nome', + }, + ], + }, + self.owner_token) + self.assertEqual( + response.status_code, + status.HTTP_400_BAD_REQUEST) + self.assertEqual( + len(content_data.get('entities')), + 1) + + def test_entities_no_valid_2(self): + example = RepositoryExample.objects.create( + repository_update=self.repository.current_update(), + text='my name is douglas') + RepositoryExampleEntity.objects.create( + repository_example=self.example, + start=11, + end=18, + entity='name') + response, content_data = self.request( + { + 'original_example': example.id, + 'language': languages.LANGUAGE_PT, + 'text': 'meu nome é douglas', + 'entities': [ + { + 'start': 11, + 'end': 18, + 'entity': 'name', + }, + { + 'start': 0, + 'end': 3, + 'entity': 'my', + }, + ], + }, + self.owner_token) + self.assertEqual( + response.status_code, + status.HTTP_400_BAD_REQUEST) + self.assertEqual( + len(content_data.get('entities')), + 1) + + def test_can_not_translate_to_same_language(self): + response, content_data = self.request( + { + 'original_example': self.example.id, + 'language': self.example.repository_update.language, + 'text': 'oi', + 'entities': [], + }, + self.owner_token) + self.assertEqual( + response.status_code, + status.HTTP_400_BAD_REQUEST) + self.assertIn( + 'language', + content_data.keys()) + + +class RepositoryTranslatedExampleRetrieveTestCase(TestCase): + def setUp(self): + self.factory = RequestFactory() + + self.owner, self.owner_token = create_user_and_token('owner') + + self.repository = Repository.objects.create( + owner=self.owner, + name='Testing', + slug='test', + language=languages.LANGUAGE_EN) + self.example = RepositoryExample.objects.create( + repository_update=self.repository.current_update(), + text='hi') + self.translated = RepositoryTranslatedExample.objects.create( + original_example=self.example, + language=languages.LANGUAGE_PT, + text='oi') + + self.private_repository = Repository.objects.create( + owner=self.owner, + name='Private', + slug='private', + language=languages.LANGUAGE_EN, + is_private=True) + self.private_example = RepositoryExample.objects.create( + repository_update=self.private_repository.current_update(), + text='hi') + self.private_translated = RepositoryTranslatedExample.objects.create( + original_example=self.private_example, + language=languages.LANGUAGE_PT, + text='oi') + + def request(self, translated, token): + authorization_header = { + 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), + } + request = self.factory.get( + '/v2/translation/{}/'.format(translated.id), + **authorization_header) + response = RepositoryTranslatedExampleViewSet.as_view( + {'get': 'retrieve'})(request, pk=translated.id) + response.render() + content_data = json.loads(response.content) + return (response, content_data,) + + def test_okay(self): + response, content_data = self.request( + self.translated, + self.owner_token) + self.assertEqual( + response.status_code, + status.HTTP_200_OK) + self.assertEqual( + content_data.get('id'), + self.translated.id) + + def test_private_okay(self): + response, content_data = self.request( + self.private_translated, + self.owner_token) + self.assertEqual( + response.status_code, + status.HTTP_200_OK) + self.assertEqual( + content_data.get('id'), + self.private_translated.id) + + def test_forbidden(self): + user, user_token = create_user_and_token() + + response, content_data = self.request( + self.private_translated, + user_token) + self.assertEqual( + response.status_code, + status.HTTP_403_FORBIDDEN) + + +class RepositoryTranslatedExampleDestroyTestCase(TestCase): + def setUp(self): + self.factory = RequestFactory() + + self.owner, self.owner_token = create_user_and_token('owner') + + self.repository = Repository.objects.create( + owner=self.owner, + name='Testing', + slug='test', + language=languages.LANGUAGE_EN) + self.example = RepositoryExample.objects.create( + repository_update=self.repository.current_update(), + text='hi') + self.translated = RepositoryTranslatedExample.objects.create( + original_example=self.example, + language=languages.LANGUAGE_PT, + text='oi') + + def request(self, translated, token): + authorization_header = { + 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), + } + request = self.factory.delete( + '/v2/translation/{}/'.format(translated.id), + **authorization_header) + response = RepositoryTranslatedExampleViewSet.as_view( + {'delete': 'destroy'})(request, pk=translated.id) + return response + + def test_okay(self): + response = self.request( + self.translated, + self.owner_token) + self.assertEqual( + response.status_code, + status.HTTP_204_NO_CONTENT) + + def test_forbidden(self): + user, user_token = create_user_and_token() + + response = self.request( + self.translated, + user_token) + self.assertEqual( + response.status_code, + status.HTTP_403_FORBIDDEN) + + +class TranslationsViewTest(TestCase): + def setUp(self): + self.factory = RequestFactory() + + self.owner, self.owner_token = create_user_and_token('owner') + + self.repository = Repository.objects.create( + owner=self.owner, + name='Testing', + slug='test', + language=languages.LANGUAGE_EN) + self.example = RepositoryExample.objects.create( + repository_update=self.repository.current_update(), + text='hi') + self.translated = RepositoryTranslatedExample.objects.create( + original_example=self.example, + language=languages.LANGUAGE_PT, + text='oi') + + def request(self, data, user_token=None): + authorization_header = { + 'HTTP_AUTHORIZATION': 'Token {}'.format(user_token.key), + } if user_token else {} + request = self.factory.get( + '/v2/translation/', + data, + **authorization_header) + response = RepositoryTranslatedExampleViewSet.as_view( + {'get': 'list'} + )(request) + response.render() + content_data = json.loads(response.content) + return (response, content_data,) + + def test_okay(self): + response, content_data = self.request({ + 'repository_uuid': self.repository.uuid, + }) + self.assertEqual( + response.status_code, + status.HTTP_200_OK) + self.assertEqual( + content_data.get('count'), + 1) + + def test_repository_not_found(self): + response, content_data = self.request({ + 'repository_uuid': uuid.uuid4(), + }) + self.assertEqual( + response.status_code, + status.HTTP_404_NOT_FOUND) + + def test_repository_uuid_invalid(self): + response, content_data = self.request({ + 'repository_uuid': 'invalid', + }) + self.assertEqual( + response.status_code, + status.HTTP_404_NOT_FOUND) + + def test_forbidden(self): + private_repository = Repository.objects.create( + owner=self.owner, + name='Testing', + slug='private', + language=languages.LANGUAGE_EN, + is_private=True) + + response, content_data = self.request({ + 'repository_uuid': private_repository.uuid, + }) + self.assertEqual( + response.status_code, + status.HTTP_403_FORBIDDEN) + + user, user_token = create_user_and_token('user') + response, content_data = self.request( + { + 'repository_uuid': private_repository.uuid, + }, + user_token) + self.assertEqual( + response.status_code, + status.HTTP_403_FORBIDDEN) + + def test_filter_from_language(self): + example = RepositoryExample.objects.create( + repository_update=self.repository.current_update( + languages.LANGUAGE_ES), + text='hola') + translated = RepositoryTranslatedExample.objects.create( + original_example=example, + language=languages.LANGUAGE_PT, + text='oi') + + response, content_data = self.request({ + 'repository_uuid': self.repository.uuid, + 'from_language': self.example.repository_update.language, + }) + self.assertEqual( + response.status_code, + status.HTTP_200_OK) + self.assertEqual( + content_data.get('count'), + 1) + self.assertEqual( + content_data.get('results')[0].get('id'), + self.translated.id) + + response, content_data = self.request({ + 'repository_uuid': self.repository.uuid, + 'from_language': example.repository_update.language, + }) + self.assertEqual( + response.status_code, + status.HTTP_200_OK) + self.assertEqual( + content_data.get('count'), + 1) + self.assertEqual( + content_data.get('results')[0].get('id'), + translated.id) + + def test_filter_to_language(self): + example = RepositoryExample.objects.create( + repository_update=self.repository.current_update( + languages.LANGUAGE_ES), + text='hola') + RepositoryTranslatedExample.objects.create( + original_example=example, + language=languages.LANGUAGE_PT, + text='oi') + + response, content_data = self.request({ + 'repository_uuid': self.repository.uuid, + 'to_language': self.translated.language, + }) + self.assertEqual( + response.status_code, + status.HTTP_200_OK) + self.assertEqual( + content_data.get('count'), + 2) + + response, content_data = self.request({ + 'repository_uuid': self.repository.uuid, + 'to_language': languages.LANGUAGE_DE, + }) + self.assertEqual( + response.status_code, + status.HTTP_200_OK) + self.assertEqual( + content_data.get('count'), + 0) diff --git a/bothub/api/v2/translation/__init__.py b/bothub/api/v2/translation/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/bothub/api/v2/translation/filters.py b/bothub/api/v2/translation/filters.py new file mode 100644 index 00000000..05beb81e --- /dev/null +++ b/bothub/api/v2/translation/filters.py @@ -0,0 +1,50 @@ +from rest_framework.exceptions import NotFound +from rest_framework.exceptions import PermissionDenied +from django.utils.translation import gettext as _ +from django.core.exceptions import ValidationError as DjangoValidationError +from django_filters import rest_framework as filters + +from bothub.common.models import Repository +from bothub.common.models import RepositoryTranslatedExample + + +class TranslationsFilter(filters.FilterSet): + class Meta: + model = RepositoryTranslatedExample + fields = [] + + repository_uuid = filters.CharFilter( + field_name='repository_uuid', + method='filter_repository_uuid', + required=True, + help_text=_('Repository\'s UUID')) + from_language = filters.CharFilter( + field_name='language', + method='filter_from_language', + help_text='Filter by original language') + to_language = filters.CharFilter( + field_name='language', + method='filter_to_language', + help_text='Filter by translated language') + + def filter_repository_uuid(self, queryset, name, value): + request = self.request + try: + repository = Repository.objects.get(uuid=value) + authorization = repository.get_user_authorization(request.user) + if not authorization.can_read: + raise PermissionDenied() + return RepositoryTranslatedExample.objects.filter( + original_example__repository_update__repository=repository) + except Repository.DoesNotExist: + raise NotFound( + _('Repository {} does not exist').format(value)) + except DjangoValidationError: + raise NotFound(_('Invalid repository_uuid')) + + def filter_from_language(self, queryset, name, value): + return queryset.filter( + original_example__repository_update__language=value) + + def filter_to_language(self, queryset, name, value): + return queryset.filter(language=value) diff --git a/bothub/api/v2/translation/permissions.py b/bothub/api/v2/translation/permissions.py new file mode 100644 index 00000000..bae22024 --- /dev/null +++ b/bothub/api/v2/translation/permissions.py @@ -0,0 +1,12 @@ +from rest_framework import permissions + +from bothub.api.v2 import READ_METHODS + + +class RepositoryTranslatedExamplePermission(permissions.BasePermission): + def has_object_permission(self, request, view, obj): + repository = obj.original_example.repository_update.repository + authorization = repository.get_user_authorization(request.user) + if request.method in READ_METHODS: + return authorization.can_read + return authorization.can_contribute diff --git a/bothub/api/v2/translation/serializers.py b/bothub/api/v2/translation/serializers.py new file mode 100644 index 00000000..0ff6cc7b --- /dev/null +++ b/bothub/api/v2/translation/serializers.py @@ -0,0 +1,112 @@ +from rest_framework import serializers + +from django.utils.translation import gettext as _ + +from bothub.api.v2.fields import EntityValueField +from bothub.common.languages import LANGUAGE_CHOICES +from bothub.common.models import RepositoryTranslatedExample +from bothub.common.models import RepositoryExample +from bothub.common.models import RepositoryTranslatedExampleEntity +from bothub.api.v2.translation.validators import \ + CanContributeInRepositoryExampleValidator +from bothub.api.v2.translation.validators import \ + CanContributeInRepositoryTranslatedExampleValidator +from bothub.api.v2.translation.validators import \ + TranslatedExampleEntitiesValidator +from bothub.api.v2.translation.validators import \ + TranslatedExampleLanguageValidator + + +class RepositoryTranslatedExampleEntitySeralizer(serializers.ModelSerializer): + class Meta: + model = RepositoryTranslatedExampleEntity + fields = [ + 'id', + 'repository_translated_example', + 'start', + 'end', + 'entity', + 'created_at', + 'value', + ] + ref_name = None + + repository_translated_example = serializers.PrimaryKeyRelatedField( + queryset=RepositoryTranslatedExample.objects, + validators=[ + CanContributeInRepositoryTranslatedExampleValidator(), + ], + help_text='Example translation ID', + required=False) + entity = serializers.SerializerMethodField(required=False) + value = serializers.SerializerMethodField(required=False) + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + if kwargs.get('data') == 'POST': + self.fields['entity'] = EntityValueField() + + def get_entity(self, obj): + return obj.entity.value + + def get_value(self, obj): + return obj.value + + +class RepositoryTranslatedExampleSerializer(serializers.ModelSerializer): + class Meta: + model = RepositoryTranslatedExample + fields = [ + 'id', + 'original_example', + 'from_language', + 'language', + 'text', + 'has_valid_entities', + 'entities', + 'created_at', + ] + ref_name = None + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + if kwargs['context'].get('request').stream: + self.fields['entities'] = \ + RepositoryTranslatedExampleEntitySeralizer( + many=True, + style={'text_field': 'text'}, + data='POST' + ) + self.validators.append(TranslatedExampleEntitiesValidator()) + self.validators.append(TranslatedExampleLanguageValidator()) + + original_example = serializers.PrimaryKeyRelatedField( + queryset=RepositoryExample.objects, + validators=[ + CanContributeInRepositoryExampleValidator(), + ], + help_text=_('Example\'s ID')) + from_language = serializers.SerializerMethodField(required=False) + language = serializers.ChoiceField( + LANGUAGE_CHOICES, + label=_('Language')) + has_valid_entities = serializers.SerializerMethodField() + entities = RepositoryTranslatedExampleEntitySeralizer( + many=True, + style={'text_field': 'text'}) + + def get_from_language(self, obj): + return obj.original_example.repository_update.language + + def get_has_valid_entities(self, obj): + return obj.has_valid_entities + + def create(self, validated_data): + entities_data = validated_data.pop('entities') + + translated = self.Meta.model.objects.create(**validated_data) + for entity_data in entities_data: + RepositoryTranslatedExampleEntity.objects.create( + repository_translated_example=translated, + **entity_data) + return translated diff --git a/bothub/api/v2/translation/validators.py b/bothub/api/v2/translation/validators.py new file mode 100644 index 00000000..6c52550f --- /dev/null +++ b/bothub/api/v2/translation/validators.py @@ -0,0 +1,63 @@ +from django.utils.translation import gettext as _ +from rest_framework.exceptions import PermissionDenied +from rest_framework.exceptions import ValidationError + +from bothub.common.models import RepositoryTranslatedExample + + +class CanContributeInRepositoryExampleValidator(object): + def __call__(self, value): + repository = value.repository_update.repository + user_authorization = repository.get_user_authorization( + self.request.user) + if not user_authorization.can_contribute: + raise PermissionDenied( + _('You can\'t contribute in this repository')) + + def set_context(self, serializer): + self.request = serializer.context.get('request') + + +class CanContributeInRepositoryTranslatedExampleValidator(object): + def __call__(self, value): + repository = value.original_example.repository_update.repository + user_authorization = repository.get_user_authorization( + self.request.user) + if not user_authorization.can_contribute: + raise PermissionDenied( + _('You can\'t contribute in this repository')) + + def set_context(self, serializer): + self.request = serializer.context.get('request') + + +class TranslatedExampleEntitiesValidator(object): + def __call__(self, attrs): + original_example = attrs.get('original_example') + entities_list = list(map(lambda x: dict(x), attrs.get('entities'))) + original_entities_list = list(map( + lambda x: x.to_dict, + original_example.entities.all())) + entities_valid = RepositoryTranslatedExample.same_entities_validator( + entities_list, + original_entities_list) + if not entities_valid: + raise ValidationError({'entities': _( + 'Entities need to match from the original content. ' + + 'Entities: {0}. Original entities: {1}.').format( + RepositoryTranslatedExample.count_entities( + entities_list, + to_str=True), + RepositoryTranslatedExample.count_entities( + original_entities_list, + to_str=True), + )}) + + +class TranslatedExampleLanguageValidator(object): + def __call__(self, attrs): + original_example = attrs.get('original_example') + language = attrs.get('language') + if original_example.repository_update.language == language: + raise ValidationError({'language': _( + 'Can\'t translate to the same language')}) diff --git a/bothub/api/v2/translation/views.py b/bothub/api/v2/translation/views.py new file mode 100644 index 00000000..1bb77517 --- /dev/null +++ b/bothub/api/v2/translation/views.py @@ -0,0 +1,52 @@ +from rest_framework.viewsets import GenericViewSet +from rest_framework import mixins +from rest_framework import permissions +from bothub.common.models import RepositoryTranslatedExample + +from bothub.api.v2.translation.permissions import \ + RepositoryTranslatedExamplePermission +from bothub.api.v2.translation.serializers import \ + RepositoryTranslatedExampleSerializer +from bothub.api.v2.translation.filters import TranslationsFilter + + +class RepositoryTranslatedExampleViewSet( + mixins.CreateModelMixin, + mixins.ListModelMixin, + mixins.RetrieveModelMixin, + mixins.UpdateModelMixin, + mixins.DestroyModelMixin, + GenericViewSet): + """ + Manager example translation. + + list: + Get example translation data. + + retrieve: + Get example translation data. + + update: + Update example translation. + + partial_update: + Update, partially, example translation. + + delete: + Delete example translation. + """ + queryset = RepositoryTranslatedExample.objects + serializer_class = RepositoryTranslatedExampleSerializer + permission_classes = [ + permissions.IsAuthenticatedOrReadOnly, + RepositoryTranslatedExamplePermission, + ] + + def create(self, request, *args, **kwargs): + self.permission_classes = [permissions.IsAuthenticated] + return super().create(request, *args, **kwargs) + + def list(self, request, *args, **kwargs): + self.queryset = RepositoryTranslatedExample.objects.all() + self.filter_class = TranslationsFilter + return super().list(request, *args, **kwargs) From 4ffcf4bba4f09ab975ddfbaa897f72f883c609ff Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Tue, 13 Aug 2019 14:13:20 -0300 Subject: [PATCH 115/207] Updated Pipfile --- Pipfile.lock | 77 ++++++++++++++++++---------------------------------- 1 file changed, 26 insertions(+), 51 deletions(-) diff --git a/Pipfile.lock b/Pipfile.lock index d25e18b5..c4ab89ec 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "03fafdda3043ea074c6300a77ce2c6abd9921ccb0273328f9c801f18821510d3" + "sha256": "5f230c8e911d5f0f91321351555b3277e4a6ce71b6fe1843271cefaf6f11559e" }, "pipfile-spec": 6, "requires": { @@ -234,7 +234,6 @@ "sha256:6f98a7b9397e206d78cc01df10131398f1c8b8510a2f4d97d9abd82e1aacdd80", "sha256:d9338df12903bbf5d65a0e4e87c2161968b10d2e489652bb47001d82a9b028b4" ], - "index": "pypi", "version": "==2.4.2" }, "python-decouple": { @@ -262,35 +261,34 @@ }, "ruamel.yaml": { "hashes": [ - "sha256:4c1dbad22790b5ea8587c2a0cae97ebc7a9d0d88de5d0edb70dea2eab7d8534a", - "sha256:eb4b1ffd095785c50f110118cb6f7bb9cd011ecc013b014436d38b7f8fb7afa9" + "sha256:547aeab5c51c93bc750ed2a320c1559b605bde3aa569216aa75fd91d8a1c4623", + "sha256:c5e239b6a4f26baabb2e22b145582a7d99ae9d4ebb8902291365a61ed38faa7f" ], - "version": "==0.16.0" + "version": "==0.16.1" }, "ruamel.yaml.clib": { "hashes": [ - "sha256:32c37bdc7ee5fbc5e794b497b98f98ecc12e1f1541cdd3bbd65f8ec32e0270d2", - "sha256:385b70734435d2f66f00823d4e224c1a4b53dfeaf9ded3a655a6a2f9c229b1f6", - "sha256:4040ddea350698138e341395508b8dd7610b2312177cb41c8db2b6260adee348", - "sha256:4dc088e55e0cc3f8c18652e830e3ecff159425f01327de4d94e5ce473fdcd2f8", - "sha256:53768934bc28ce07ca82c02d9db6717ae9bad4cdf9511d3a3e6d1b576235d04e", - "sha256:53fd2ef53be8301707662f4c353731d97a4cb2b372972b7dcd73ef245dbab9e9", - "sha256:5712728e6ba56d3b93f5f99a175760c778420caae714687592548c4f7699782e", - "sha256:66df3233e5cca3528be2a700f2a54e26262dde6d5e22b34953e7f44785857c8c", - "sha256:750a15f07178d91204ce4baffb16697cef4c8f583495d4f0fec52902dad8e7fc", - "sha256:820ec13201ed5c015dc74ea7087b2c5c56b8aeb51af4b7d7c859e0b45c07f035", - "sha256:8dcab8a09c17a030d046749eb97ed9a81e02bb642d7816e8757fc5a3016af89d", - "sha256:9e1acd628f2bf601fd4df69523476ee4640be8ba7d9aff8f04cd66a1ae07f119", - "sha256:b31bc078c9bac3dbb5855e94eb382aeef23076bf3d1a2d02ee8d91c55567cb08", - "sha256:b7a681e2d6dbd147ec9808cb1a736c1ef96bc2c693f54e0fc01fe0d10409bd88", - "sha256:c1333e8911c29c6e209db117345141d5fcb772464d62cac3e117912a965d9619", - "sha256:d583e7b9646418dff5ee0e36875b3cabc3d0fb925dfdeec239697c583388f9b2", - "sha256:da610ff9feeb075641128ce40881d2ac3c8e57e7ea04636169b0c3b5e8f711f7", - "sha256:e9b6ebb62806817b01e9eea9fc7da57c12557e44e94e79f5fa82eca4bc7fad60", - "sha256:f36035f1c0b6a7a20010e98b582d38272514a77f34cd45ec0d2847abaa89ac78" + "sha256:0bbe19d3e099f8ba384e1846e6b54f245f58aeec8700edbbf9abb87afa54fd82", + "sha256:2f38024592613f3a8772bbc2904be027d9abf463518ba145f2d0c8e6da27009f", + "sha256:44449b3764a3f75815eea8ae5930b98e8326be64a90b0f782747318f861abfe0", + "sha256:5710be9a357801c31c1eaa37b9bc92d38176d785af5b2f0c9751385c5dc9659a", + "sha256:5a089acb6833ed5f412e24cbe3e665683064c1429824d2819137b5ade54435c3", + "sha256:6143386ddd61599ea081c012a69a16e5bdd7b3c6c231bd039534365a48940f30", + "sha256:6726aaf851f5f9e4cbdd3e1e414bc700bdd39220e8bc386415fd41c87b1b53c2", + "sha256:68fbc3b5d94d145a391452f886ae5fca240cb7e3ab6bd66e1a721507cdaac28a", + "sha256:75ebddf99ba9e0b48f32b5bdcf9e5a2b84c017da9e0db7bf11995fa414aa09cd", + "sha256:79948a6712baa686773a43906728e20932c923f7b2a91be7347993be2d745e55", + "sha256:8a2dd8e8b08d369558cade05731172c4b5e2f4c5097762c6b352bd28fd9f9dc4", + "sha256:c747acdb5e8c242ab2280df6f0c239e62838af4bee647031d96b3db2f9cefc04", + "sha256:cadc8eecd27414dca30366b2535cb5e3f3b47b4e2d6be7a0b13e4e52e459ff9f", + "sha256:cee86ecc893a6a8ecaa7c6a9c2d06f75f614176210d78a5f155f8e78d6989509", + "sha256:e59af39e895aff28ee5f55515983cab3466d1a029c91c04db29da1c0f09cf333", + "sha256:eee7ecd2eee648884fae6c51ae50c814acdcc5d6340dc96c970158aebcd25ac6", + "sha256:ef8d4522d231cb9b29f6cdd0edc8faac9d9715c60dc7becbd6eb82c915a98e5b", + "sha256:f504d45230cc9abf2810623b924ae048b224a90adb01f97db4e766cfdda8e6eb" ], "markers": "platform_python_implementation == 'CPython' and python_version < '3.8'", - "version": "==0.1.0" + "version": "==0.1.2" }, "six": { "hashes": [ @@ -332,13 +330,6 @@ "markers": "sys_platform == 'darwin'", "version": "==0.1.0" }, - "attrs": { - "hashes": [ - "sha256:69c0dbf2ed392de1cb5ec704444b08a5ef81680a61cb899dc08127123af36a79", - "sha256:f0b870f674851ecbfbbbd364d6b5cbdff9dcedbc7f3f5e18a6891057f21fe399" - ], - "version": "==19.1.0" - }, "autopep8": { "hashes": [ "sha256:4d8eec30cc81bc5617dbf1218201d770dc35629363547f17577c61683ccfb3ee" @@ -430,10 +421,10 @@ }, "jedi": { "hashes": [ - "sha256:53c850f1a7d3cfcd306cc513e2450a54bdf5cacd7604b74e42dd1f0758eaaf36", - "sha256:e07457174ef7cb2342ff94fa56484fe41cec7ef69b0059f01d3f812379cb6f7c" + "sha256:786b6c3d80e2f06fd77162a07fed81b8baa22dde5d62896a790a331d6ac21a27", + "sha256:ba859c74fa3c966a22f2aeebe1b74ee27e2a462f56d3f5f7ca4a59af61bfe42e" ], - "version": "==0.14.1" + "version": "==0.15.1" }, "mccabe": { "hashes": [ @@ -442,14 +433,6 @@ ], "version": "==0.6.1" }, - "packaging": { - "hashes": [ - "sha256:a7ac867b97fdc07ee80a8058fe4435ccd274ecc3b0ed61d852d7d53055528cf9", - "sha256:c491ca87294da7cc01902edbe30a5bc6c4c28172b5138ab4e4aa1b9d7bfaeafe" - ], - "index": "pypi", - "version": "==19.1" - }, "parso": { "hashes": [ "sha256:63854233e1fadb5da97f2744b6b24346d2750b85965e7e399bec1620232797dc", @@ -508,14 +491,6 @@ ], "version": "==2.4.2" }, - "pyparsing": { - "hashes": [ - "sha256:6f98a7b9397e206d78cc01df10131398f1c8b8510a2f4d97d9abd82e1aacdd80", - "sha256:d9338df12903bbf5d65a0e4e87c2161968b10d2e489652bb47001d82a9b028b4" - ], - "index": "pypi", - "version": "==2.4.2" - }, "six": { "hashes": [ "sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c", From c9d6c010e9366107983aa1bc33f24eb0c1d5a339 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Tue, 13 Aug 2019 14:18:28 -0300 Subject: [PATCH 116/207] Migration Repository Update v1 to v2 --- bothub/api/v1/views.py | 6 +++ bothub/api/v2/repository/filters.py | 29 +++++++++++ bothub/api/v2/repository/permissions.py | 12 +++++ bothub/api/v2/repository/serializers.py | 23 +++++++++ bothub/api/v2/repository/views.py | 17 +++++++ bothub/api/v2/routers.py | 2 + bothub/api/v2/tests/test_repository.py | 68 +++++++++++++++++++++++++ 7 files changed, 157 insertions(+) diff --git a/bothub/api/v1/views.py b/bothub/api/v1/views.py index a1431304..afc78a71 100644 --- a/bothub/api/v1/views.py +++ b/bothub/api/v1/views.py @@ -1294,6 +1294,12 @@ class RepositoryEntitiesViewSet( ] +@method_decorator( + name='list', + decorator=swagger_auto_schema( + deprecated=True, + ) +) class RepositoryUpdatesViewSet( mixins.ListModelMixin, GenericViewSet): diff --git a/bothub/api/v2/repository/filters.py b/bothub/api/v2/repository/filters.py index 0f9180f3..9445f7e4 100644 --- a/bothub/api/v2/repository/filters.py +++ b/bothub/api/v2/repository/filters.py @@ -7,6 +7,7 @@ from bothub.common.models import Repository from bothub.common.models import RepositoryAuthorization from bothub.common.models import RequestRepositoryAuthorization +from bothub.common.models import RepositoryUpdate class RepositoriesFilter(filters.FilterSet): @@ -75,3 +76,31 @@ def filter_repository_uuid(self, queryset, name, value): _('Repository {} does not exist').format(value)) except DjangoValidationError: raise NotFound(_('Invalid repository UUID')) + + +class RepositoryUpdatesFilter(filters.FilterSet): + class Meta: + model = RepositoryUpdate + fields = [ + 'repository_uuid', + ] + + repository_uuid = filters.CharFilter( + field_name='repository_uuid', + required=True, + method='filter_repository_uuid', + help_text=_('Repository\'s UUID')) + + def filter_repository_uuid(self, queryset, name, value): + request = self.request + try: + repository = Repository.objects.get(uuid=value) + authorization = repository.get_user_authorization(request.user) + if not authorization.can_read: + raise PermissionDenied() + return queryset.filter(repository=repository) + except Repository.DoesNotExist: + raise NotFound( + _('Repository {} does not exist').format(value)) + except DjangoValidationError: + raise NotFound(_('Invalid repository UUID')) diff --git a/bothub/api/v2/repository/permissions.py b/bothub/api/v2/repository/permissions.py index 653f4f57..61631893 100644 --- a/bothub/api/v2/repository/permissions.py +++ b/bothub/api/v2/repository/permissions.py @@ -33,3 +33,15 @@ def has_object_permission(self, request, view, obj): if request.method in READ_METHODS: return authorization.can_read return authorization.can_contribute + + +class RepositoryUpdateHasPermission(permissions.BasePermission): + def has_object_permission(self, request, view, obj): + authorization = obj.repository.get_user_authorization(request.user) + if request.method in READ_METHODS: + return authorization.can_read + if request.user.is_authenticated: + if request.method in WRITE_METHODS: + return authorization.can_write + return authorization.is_admin + return False diff --git a/bothub/api/v2/repository/serializers.py b/bothub/api/v2/repository/serializers.py index 2e4a2f0e..590d978b 100644 --- a/bothub/api/v2/repository/serializers.py +++ b/bothub/api/v2/repository/serializers.py @@ -24,6 +24,7 @@ from bothub.common.models import RepositoryTranslatedExample from bothub.common.models import RepositoryExample from bothub.common.models import RepositoryTranslatedExampleEntity +from bothub.common.models import RepositoryUpdate from bothub.common.languages import LANGUAGE_CHOICES from .validators import CanContributeInRepositoryTranslatedExampleValidator @@ -549,3 +550,25 @@ def create(self, validated_data): entity_serializer.is_valid(raise_exception=True) entity_serializer.save() return example + + +class RepositoryUpdateSerializer(serializers.ModelSerializer): + class Meta: + model = RepositoryUpdate + fields = [ + 'id', + 'repository', + 'language', + 'created_at', + 'by', + 'by__nickname', + 'training_started_at', + 'trained_at', + 'failed_at', + ] + ref_name = None + + by__nickname = serializers.SlugRelatedField( + source='by', + slug_field='nickname', + read_only=True) diff --git a/bothub/api/v2/repository/views.py b/bothub/api/v2/repository/views.py index c1df7915..a90b720b 100644 --- a/bothub/api/v2/repository/views.py +++ b/bothub/api/v2/repository/views.py @@ -24,6 +24,7 @@ from bothub.common.models import RepositoryCategory from bothub.common.models import RequestRepositoryAuthorization from bothub.common.models import RepositoryExample +from bothub.common.models import RepositoryUpdate from ..metadata import Metadata from .serializers import RepositorySerializer @@ -35,12 +36,15 @@ from .serializers import RepositoryAuthorizationSerializer from .serializers import RequestRepositoryAuthorizationSerializer from .serializers import RepositoryExampleSerializer +from .serializers import RepositoryUpdateSerializer from .permissions import RepositoryPermission from .permissions import RepositoryAdminManagerAuthorization from .permissions import RepositoryExamplePermission +from .permissions import RepositoryUpdateHasPermission from .filters import RepositoriesFilter from .filters import RepositoryAuthorizationFilter from .filters import RepositoryAuthorizationRequestsFilter +from .filters import RepositoryUpdatesFilter class RepositoryViewSet( @@ -360,3 +364,16 @@ def perform_destroy(self, obj): if obj.deleted_in: raise APIException(_('Example already deleted')) obj.delete() + + +class RepositoryUpdatesViewSet( + mixins.ListModelMixin, + GenericViewSet): + queryset = RepositoryUpdate.objects.filter( + training_started_at__isnull=False).order_by('-trained_at') + serializer_class = RepositoryUpdateSerializer + filter_class = RepositoryUpdatesFilter + permission_classes = [ + IsAuthenticated, + RepositoryUpdateHasPermission, + ] diff --git a/bothub/api/v2/routers.py b/bothub/api/v2/routers.py index 6b40fd6c..710d96e8 100644 --- a/bothub/api/v2/routers.py +++ b/bothub/api/v2/routers.py @@ -9,6 +9,7 @@ from .repository.views import RepositoryAuthorizationViewSet from .repository.views import RepositoryAuthorizationRequestsViewSet from .repository.views import RepositoryExampleViewSet +from .repository.views import RepositoryUpdatesViewSet from .examples.views import ExamplesViewSet from .evaluate.views import EvaluateViewSet from .evaluate.views import ResultsListViewSet @@ -108,6 +109,7 @@ def get_lookup_regex(self, viewset, lookup_prefix=''): RepositoryAuthorizationRequestsViewSet ) router.register('repository/example', RepositoryExampleViewSet) +router.register('repository/updates', RepositoryUpdatesViewSet) router.register('evaluate/results', ResultsListViewSet) router.register('evaluate', EvaluateViewSet) router.register('account/login', LoginViewSet) diff --git a/bothub/api/v2/tests/test_repository.py b/bothub/api/v2/tests/test_repository.py index 0a5ccbcb..e061e677 100644 --- a/bothub/api/v2/tests/test_repository.py +++ b/bothub/api/v2/tests/test_repository.py @@ -29,6 +29,7 @@ from bothub.api.v2.repository.views import \ RepositoryAuthorizationRequestsViewSet from bothub.api.v2.repository.views import RepositoryExampleViewSet +from bothub.api.v2.repository.views import RepositoryUpdatesViewSet from bothub.api.v2.repository.serializers import RepositorySerializer @@ -1925,3 +1926,70 @@ def test_intent_with_special_char(self): self.assertEqual( len(content_data.get('intent')), 1) + + +class UpdatesTestCase(TestCase): + def setUp(self): + self.factory = RequestFactory() + + self.owner, self.owner_token = create_user_and_token('owner') + + self.repository = Repository.objects.create( + owner=self.owner, + name='Testing', + slug='test', + language=languages.LANGUAGE_EN) + current_update = self.repository.current_update() + RepositoryExample.objects.create( + repository_update=current_update, + text='my name is Douglas', + intent='greet') + RepositoryExample.objects.create( + repository_update=current_update, + text='my name is John', + intent='greet') + current_update.start_training(self.owner) + + def request(self, data, token=None): + authorization_header = { + 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), + } if token else {} + request = self.factory.get( + '/v2/repository/updates/', + data, + **authorization_header) + response = RepositoryUpdatesViewSet.as_view( + {'get': 'list'})(request) + response.render() + content_data = json.loads(response.content) + return (response, content_data,) + + def test_okay(self): + response, content_data = self.request( + { + 'repository_uuid': str(self.repository.uuid), + }, + self.owner_token) + self.assertEqual( + response.status_code, + status.HTTP_200_OK) + self.assertEqual( + content_data.get('count'), + 1) + + def test_not_authenticated(self): + response, content_data = self.request( + { + 'repository_uuid': str(self.repository.uuid), + }) + self.assertEqual( + response.status_code, + status.HTTP_401_UNAUTHORIZED) + + def test_without_repository(self): + response, content_data = self.request( + {}, + self.owner_token) + self.assertEqual( + response.status_code, + status.HTTP_400_BAD_REQUEST) From bbc7eab00ec849a8f8f1adc7b30c1042862189ed Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Wed, 14 Aug 2019 18:06:42 -0300 Subject: [PATCH 117/207] Removed Douglas User --- README.md | 1 - bothub/api/v1/tests/test_example.py | 18 ++++---- bothub/api/v1/tests/test_repository.py | 4 +- bothub/api/v1/tests/test_translate.py | 12 ++--- bothub/api/v1/tests/test_updates.py | 2 +- bothub/api/v2/tests/test_repository.py | 14 +++--- bothub/api/v2/tests/test_translation.py | 12 ++--- .../commands/fill_db_using_fake_data.py | 10 +--- bothub/common/tests.py | 46 +++++++++---------- bothub/urls.py | 12 ++--- 10 files changed, 62 insertions(+), 69 deletions(-) diff --git a/README.md b/README.md index 802923c2..f79eb9d5 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,6 @@ Run ```pipenv run python ./manage.py fill_db_using_fake_data``` to fill database | nickname | email | password | is superuser | |---|---|---|---| | admin | admin@bothub.it | admin | yes | -| douglas | douglas@bothub.it | douglas | no | | user | user@bothub.it | user | no | diff --git a/bothub/api/v1/tests/test_example.py b/bothub/api/v1/tests/test_example.py index 3c95e23b..0a9fd157 100644 --- a/bothub/api/v1/tests/test_example.py +++ b/bothub/api/v1/tests/test_example.py @@ -153,7 +153,7 @@ def test_with_entities(self): self.owner_token, { 'repository': str(self.repository.uuid), - 'text': 'my name is douglas', + 'text': 'my name is user', 'intent': 'greet', 'entities': [ { @@ -209,7 +209,7 @@ def test_with_entities_with_label(self): self.owner_token, { 'repository': str(self.repository.uuid), - 'text': 'my name is douglas', + 'text': 'my name is user', 'intent': 'greet', 'entities': [ { @@ -236,7 +236,7 @@ def test_with_entities_with_invalid_label(self): self.owner_token, { 'repository': str(self.repository.uuid), - 'text': 'my name is douglas', + 'text': 'my name is user', 'intent': 'greet', 'entities': [ { @@ -263,7 +263,7 @@ def test_with_entities_with_equal_label(self): self.owner_token, { 'repository': str(self.repository.uuid), - 'text': 'my name is douglas', + 'text': 'my name is user', 'intent': 'greet', 'entities': [ { @@ -303,7 +303,7 @@ def test_entity_with_special_char(self): self.owner_token, { 'repository': str(self.repository.uuid), - 'text': 'my name is douglas', + 'text': 'my name is user', 'intent': '', 'entities': [ { @@ -325,7 +325,7 @@ def test_intent_with_special_char(self): self.owner_token, { 'repository': str(self.repository.uuid), - 'text': 'my name is douglas', + 'text': 'my name is user', 'intent': 'nam$s', 'entities': [], }) @@ -351,7 +351,7 @@ def setUp(self): language=languages.LANGUAGE_EN) self.example = RepositoryExample.objects.create( repository_update=self.repository.current_update(), - text='my name is douglas') + text='my name is user') self.example_entity = RepositoryExampleEntity.objects.create( repository_example=self.example, start=11, @@ -612,7 +612,7 @@ def setUp(self): self.owner, self.owner_token = create_user_and_token('owner') self.user, self.user_token = create_user_and_token() - self.entity_value = 'douglas' + self.entity_value = 'user' self.repository = Repository.objects.create( owner=self.owner, @@ -621,7 +621,7 @@ def setUp(self): language=languages.LANGUAGE_EN) self.example = RepositoryExample.objects.create( repository_update=self.repository.current_update(), - text='my name is douglas') + text='my name is user') self.example_entity = RepositoryExampleEntity.objects.create( repository_example=self.example, start=11, diff --git a/bothub/api/v1/tests/test_repository.py b/bothub/api/v1/tests/test_repository.py index 920f124a..bbe808f2 100644 --- a/bothub/api/v1/tests/test_repository.py +++ b/bothub/api/v1/tests/test_repository.py @@ -641,7 +641,7 @@ def test_permission_denied_in_private_repository(self): self.user_token, { 'language': 'en', - 'text': 'My name is Douglas', + 'text': 'My name is user', }) self.assertEqual( response.status_code, @@ -653,7 +653,7 @@ def test_language_required(self): self.owner_token, { 'language': '', - 'text': 'My name is Douglas', + 'text': 'My name is user', }) self.assertEqual( response.status_code, diff --git a/bothub/api/v1/tests/test_translate.py b/bothub/api/v1/tests/test_translate.py index bf77f6d5..2f646af4 100644 --- a/bothub/api/v1/tests/test_translate.py +++ b/bothub/api/v1/tests/test_translate.py @@ -103,7 +103,7 @@ def test_forbidden(self): def test_okay_with_entities(self): example = RepositoryExample.objects.create( repository_update=self.repository.current_update(), - text='my name is douglas') + text='my name is user') RepositoryExampleEntity.objects.create( repository_example=example, start=11, @@ -113,7 +113,7 @@ def test_okay_with_entities(self): { 'original_example': example.id, 'language': languages.LANGUAGE_PT, - 'text': 'meu nome é douglas', + 'text': 'meu nome é user', 'entities': [ { 'start': 11, @@ -133,7 +133,7 @@ def test_okay_with_entities(self): def test_entities_no_valid(self): example = RepositoryExample.objects.create( repository_update=self.repository.current_update(), - text='my name is douglas') + text='my name is user') RepositoryExampleEntity.objects.create( repository_example=self.example, start=11, @@ -143,7 +143,7 @@ def test_entities_no_valid(self): { 'original_example': example.id, 'language': languages.LANGUAGE_PT, - 'text': 'meu nome é douglas', + 'text': 'meu nome é user', 'entities': [ { 'start': 11, @@ -163,7 +163,7 @@ def test_entities_no_valid(self): def test_entities_no_valid_2(self): example = RepositoryExample.objects.create( repository_update=self.repository.current_update(), - text='my name is douglas') + text='my name is user') RepositoryExampleEntity.objects.create( repository_example=self.example, start=11, @@ -173,7 +173,7 @@ def test_entities_no_valid_2(self): { 'original_example': example.id, 'language': languages.LANGUAGE_PT, - 'text': 'meu nome é douglas', + 'text': 'meu nome é user', 'entities': [ { 'start': 11, diff --git a/bothub/api/v1/tests/test_updates.py b/bothub/api/v1/tests/test_updates.py index baebd47f..84b78b60 100644 --- a/bothub/api/v1/tests/test_updates.py +++ b/bothub/api/v1/tests/test_updates.py @@ -25,7 +25,7 @@ def setUp(self): current_update = self.repository.current_update() RepositoryExample.objects.create( repository_update=current_update, - text='my name is Douglas', + text='my name is user', intent='greet') RepositoryExample.objects.create( repository_update=current_update, diff --git a/bothub/api/v2/tests/test_repository.py b/bothub/api/v2/tests/test_repository.py index 0a5ccbcb..040edc25 100644 --- a/bothub/api/v2/tests/test_repository.py +++ b/bothub/api/v2/tests/test_repository.py @@ -1350,7 +1350,7 @@ def setUp(self): language=languages.LANGUAGE_EN) self.example = RepositoryExample.objects.create( repository_update=self.repository.current_update(), - text='my name is douglas') + text='my name is user') self.example_entity = RepositoryExampleEntity.objects.create( repository_example=self.example, start=11, @@ -1743,7 +1743,7 @@ def test_with_entities(self): self.owner_token, { 'repository': str(self.repository.uuid), - 'text': 'my name is douglas', + 'text': 'my name is user', 'intent': 'greet', 'entities': [ { @@ -1799,7 +1799,7 @@ def test_with_entities_with_label(self): self.owner_token, { 'repository': str(self.repository.uuid), - 'text': 'my name is douglas', + 'text': 'my name is user', 'intent': 'greet', 'entities': [ { @@ -1826,7 +1826,7 @@ def test_with_entities_with_invalid_label(self): self.owner_token, { 'repository': str(self.repository.uuid), - 'text': 'my name is douglas', + 'text': 'my name is user', 'intent': 'greet', 'entities': [ { @@ -1853,7 +1853,7 @@ def test_with_entities_with_equal_label(self): self.owner_token, { 'repository': str(self.repository.uuid), - 'text': 'my name is douglas', + 'text': 'my name is user', 'intent': 'greet', 'entities': [ { @@ -1893,7 +1893,7 @@ def test_entity_with_special_char(self): self.owner_token, { 'repository': str(self.repository.uuid), - 'text': 'my name is douglas', + 'text': 'my name is user', 'intent': '', 'entities': [ { @@ -1915,7 +1915,7 @@ def test_intent_with_special_char(self): self.owner_token, { 'repository': str(self.repository.uuid), - 'text': 'my name is douglas', + 'text': 'my name is user', 'intent': 'nam$s', 'entities': [], }) diff --git a/bothub/api/v2/tests/test_translation.py b/bothub/api/v2/tests/test_translation.py index c8be286c..8e280806 100644 --- a/bothub/api/v2/tests/test_translation.py +++ b/bothub/api/v2/tests/test_translation.py @@ -101,7 +101,7 @@ def test_forbidden(self): def test_okay_with_entities(self): example = RepositoryExample.objects.create( repository_update=self.repository.current_update(), - text='my name is douglas') + text='my name is user') RepositoryExampleEntity.objects.create( repository_example=example, start=11, @@ -111,7 +111,7 @@ def test_okay_with_entities(self): { 'original_example': example.id, 'language': languages.LANGUAGE_PT, - 'text': 'meu nome é douglas', + 'text': 'meu nome é user', 'entities': [ { 'start': 11, @@ -131,7 +131,7 @@ def test_okay_with_entities(self): def test_entities_no_valid(self): example = RepositoryExample.objects.create( repository_update=self.repository.current_update(), - text='my name is douglas') + text='my name is user') RepositoryExampleEntity.objects.create( repository_example=self.example, start=11, @@ -141,7 +141,7 @@ def test_entities_no_valid(self): { 'original_example': example.id, 'language': languages.LANGUAGE_PT, - 'text': 'meu nome é douglas', + 'text': 'meu nome é user', 'entities': [ { 'start': 11, @@ -161,7 +161,7 @@ def test_entities_no_valid(self): def test_entities_no_valid_2(self): example = RepositoryExample.objects.create( repository_update=self.repository.current_update(), - text='my name is douglas') + text='my name is user') RepositoryExampleEntity.objects.create( repository_example=self.example, start=11, @@ -171,7 +171,7 @@ def test_entities_no_valid_2(self): { 'original_example': example.id, 'language': languages.LANGUAGE_PT, - 'text': 'meu nome é douglas', + 'text': 'meu nome é user', 'entities': [ { 'start': 11, diff --git a/bothub/common/management/commands/fill_db_using_fake_data.py b/bothub/common/management/commands/fill_db_using_fake_data.py index 7fe1cef4..19f26875 100644 --- a/bothub/common/management/commands/fill_db_using_fake_data.py +++ b/bothub/common/management/commands/fill_db_using_fake_data.py @@ -33,12 +33,6 @@ def handle(self, *args, **kwargs): password='admin', name='Admin') - douglas = User.objects.create_user( - email='douglas@bothub.it', - nickname='douglas', - password='douglas', - name='Douglas Paz') - user = User.objects.create_user( email='user@bothub.it', nickname='user', @@ -55,7 +49,7 @@ def handle(self, *args, **kwargs): # Repositories repository_1 = Repository.objects.create( - owner=douglas, + owner=user, name='Repository 1', slug='repo1', language=languages.LANGUAGE_EN) @@ -73,7 +67,7 @@ def handle(self, *args, **kwargs): for x in range(3, 46): new_repository = Repository.objects.create( - owner=random.choice([douglas, user]), + owner=user, name='Repository {}'.format(x), slug='repo{}'.format(x), language=languages.LANGUAGE_EN) diff --git a/bothub/common/tests.py b/bothub/common/tests.py index 891a866a..b88521df 100644 --- a/bothub/common/tests.py +++ b/bothub/common/tests.py @@ -30,7 +30,7 @@ def setUp(self): self.repository_update = self.repository.current_update('en') example = RepositoryExample.objects.create( repository_update=self.repository_update, - text='my name is Douglas') + text='my name is User') self.entity = RepositoryExampleEntity.objects.create( repository_example=example, start=11, @@ -38,7 +38,7 @@ def setUp(self): entity='name') def test_repository_example_entity(self): - self.assertEqual(self.entity.value, 'Douglas') + self.assertEqual(self.entity.value, 'User') def test_repository_current_update(self): update1 = self.repository.current_update('en') @@ -50,19 +50,19 @@ def test_repository_current_update(self): class TranslateTestCase(TestCase): EXPECTED_RASA_NLU_DATA = { - 'text': 'meu nome é Douglas', + 'text': 'meu nome é User', 'intent': 'greet', 'entities': [], } EXPECTED_RASA_NLU_DATA_WITH_ENTITIES = { - 'text': 'meu nome é Douglas', + 'text': 'meu nome é User', 'intent': 'greet', 'entities': [ { 'start': 11, 'end': 18, - 'value': 'Douglas', + 'value': 'User', 'entity': 'name', } ], @@ -77,7 +77,7 @@ def setUp(self): self.repository_update = self.repository.current_update('en') self.example = RepositoryExample.objects.create( repository_update=self.repository_update, - text='my name is Douglas', + text='my name is User', intent='greet') def test_new_translate(self): @@ -85,7 +85,7 @@ def test_new_translate(self): RepositoryTranslatedExample.objects.create( original_example=self.example, language=language, - text='meu nome é Douglas') + text='meu nome é User') self.assertEqual( len(self.repository.current_update(language).examples), 1) @@ -101,7 +101,7 @@ def test_translated_entity(self): translate = RepositoryTranslatedExample.objects.create( original_example=self.example, language=language, - text='meu nome é Douglas') + text='meu nome é User') RepositoryTranslatedExampleEntity.objects.create( repository_translated_example=translate, start=11, @@ -119,7 +119,7 @@ def test_valid_entities(self): translate = RepositoryTranslatedExample.objects.create( original_example=self.example, language=language, - text='meu nome é Douglas') + text='meu nome é User') RepositoryTranslatedExampleEntity.objects.create( repository_translated_example=translate, start=11, @@ -141,7 +141,7 @@ def test_invalid_count_entities(self): translate = RepositoryTranslatedExample.objects.create( original_example=self.example, language=language, - text='meu nome é Douglas') + text='meu nome é User') self.assertEqual( translate.has_valid_entities, @@ -174,7 +174,7 @@ def test_invalid_how_entities(self): translate = RepositoryTranslatedExample.objects.create( original_example=self.example, language=language, - text='meu nome é Douglas') + text='meu nome é User') RepositoryTranslatedExampleEntity.objects.create( repository_translated_example=translate, start=11, @@ -206,7 +206,7 @@ def test_invalid_many_how_entities(self): translate = RepositoryTranslatedExample.objects.create( original_example=self.example, language=language, - text='meu nome é Douglas') + text='meu nome é User') RepositoryTranslatedExampleEntity.objects.create( repository_translated_example=translate, start=11, @@ -326,7 +326,7 @@ def test_entities(self): example = RepositoryExample.objects.create( repository_update=self.repository.current_update( languages.LANGUAGE_EN), - text='my name is Douglas') + text='my name is User') RepositoryExampleEntity.objects.create( repository_example=example, start=11, @@ -841,11 +841,11 @@ def test_when_deleted(self): def test_empty_intent(self): example = RepositoryExample.objects.create( repository_update=self.repository.current_update(), - text='douglas', + text='user', intent='') RepositoryExample.objects.create( repository_update=self.repository.current_update(), - text='douglas', + text='user', intent='') RepositoryExampleEntity.objects.create( repository_example=example, @@ -968,7 +968,7 @@ def setUp(self): self.example = RepositoryExample.objects.create( repository_update=self.repository.current_update(), - text='my name is Douglas') + text='my name is User') self.example_entity_1 = RepositoryExampleEntity.objects.create( repository_example=self.example, @@ -1023,7 +1023,7 @@ def setUp(self): self.example = RepositoryExample.objects.create( repository_update=self.repository.current_update(), - text='my name is Douglas') + text='my name is User') self.example_entity_1 = RepositoryExampleEntity.objects.create( repository_example=self.example, @@ -1105,13 +1105,13 @@ def setUp(self): self.example = RepositoryExample.objects.create( repository_update=self.repository.current_update(), - text='my name is Douglas') + text='my name is User') self.example_entity_1 = RepositoryExampleEntity.objects.create( repository_example=self.example, start=11, end=18, - entity='douglas') + entity='user') entity = self.example_entity_1.entity entity.set_label('name') entity.save() @@ -1145,7 +1145,7 @@ def setUp(self): RepositoryExample.objects.create( repository_update=self.repository.current_update(), - text='my name is Douglas', + text='my name is user', intent='greet') RepositoryExample.objects.create( repository_update=self.repository.current_update(), @@ -1177,7 +1177,7 @@ def setUp(self): RepositoryExample.objects.create( repository_update=self.repository.current_update(), - text='my name is Douglas', + text='my name is user', intent='greet') RepositoryExample.objects.create( repository_update=self.repository.current_update(), @@ -1221,7 +1221,7 @@ def setUp(self): RepositoryExample.objects.create( repository_update=self.repository.current_update(), - text='my name is Douglas', + text='my name is user', intent='greet') RepositoryExample.objects.create( repository_update=self.repository.current_update(), @@ -1265,7 +1265,7 @@ def setUp(self): RepositoryExample.objects.create( repository_update=self.repository.current_update(), - text='my name is Douglas', + text='my name is user', intent='greet') def test_min_intents(self): diff --git a/bothub/urls.py b/bothub/urls.py index dad61274..028124d4 100644 --- a/bothub/urls.py +++ b/bothub/urls.py @@ -52,15 +52,15 @@ def wrapper(request): 'welcome/', render_template( 'authentication/emails/welcome.html', - name='Douglas')), + name='User')), path( 'new-role/', render_template( 'common/emails/new_role.html', - responsible_name='Douglas', + responsible_name='User', user_name='Michael', repository_name='Repository 1', - repository_url='http://localhost:8080/douglas/repo1/', + repository_url='http://localhost:8080/user/repo1/', new_role='Admin')), path( 'new-request/', @@ -73,7 +73,7 @@ def wrapper(request): 'consectetur. Praesent eleifend sit amet nulla sed ' + 'egestas. Nam ac quam lacus. Pellentesque posuere, ' + 'nisl nullam.', - repository_url='http://localhost:8080/douglas/repo1/')), + repository_url='http://localhost:8080/user/repo1/')), path( 'request-rejected/', render_template( @@ -83,8 +83,8 @@ def wrapper(request): 'request-approved/', render_template( 'common/emails/request_approved.html', - admin_name='Douglas', + admin_name='User', repository_name='Repository 1', - repository_url='http://localhost:8080/douglas/repo1/')), + repository_url='http://localhost:8080/user/repo1/')), ])), ] From c41a7a4e4840429960b192f1c5cf9502acb43c56 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Thu, 15 Aug 2019 16:01:41 -0300 Subject: [PATCH 118/207] Migrate and Refact Repository routers custom --- bothub/api/v1/views.py | 12 ++ bothub/api/v2/repository/serializers.py | 9 + bothub/api/v2/repository/views.py | 114 +++++++++++ bothub/api/v2/tests/test_repository.py | 248 ++++++++++++++++++++++++ 4 files changed, 383 insertions(+) diff --git a/bothub/api/v1/views.py b/bothub/api/v1/views.py index a1431304..334744ea 100644 --- a/bothub/api/v1/views.py +++ b/bothub/api/v1/views.py @@ -474,6 +474,12 @@ class RepositoryViewSet( RepositoryPermission, ] + @method_decorator( + name='list', + decorator=swagger_auto_schema( + deprecated=True + ) + ) @action( detail=True, methods=['GET'], @@ -534,6 +540,12 @@ def train(self, request, **kwargs): code=request.status_code) return Response(request.json()) # pragma: no cover + @method_decorator( + name='list', + decorator=swagger_auto_schema( + deprecated=True + ) + ) @action( detail=True, methods=['POST'], diff --git a/bothub/api/v2/repository/serializers.py b/bothub/api/v2/repository/serializers.py index 2e4a2f0e..fa354f5e 100644 --- a/bothub/api/v2/repository/serializers.py +++ b/bothub/api/v2/repository/serializers.py @@ -549,3 +549,12 @@ def create(self, validated_data): entity_serializer.is_valid(raise_exception=True) entity_serializer.save() return example + + +class AnalyzeTextSerializer(serializers.Serializer): + language = serializers.ChoiceField(LANGUAGE_CHOICES, required=True) + text = serializers.CharField(allow_blank=False) + + +class EvaluateSerializer(serializers.Serializer): + language = serializers.ChoiceField(LANGUAGE_CHOICES, required=True) diff --git a/bothub/api/v2/repository/views.py b/bothub/api/v2/repository/views.py index c1df7915..acda6de9 100644 --- a/bothub/api/v2/repository/views.py +++ b/bothub/api/v2/repository/views.py @@ -5,7 +5,9 @@ from django.utils.translation import gettext as _ from drf_yasg import openapi from drf_yasg.utils import swagger_auto_schema +from rest_framework.decorators import action from rest_framework.exceptions import ValidationError +from rest_framework.exceptions import PermissionDenied from rest_framework.response import Response from rest_framework.viewsets import GenericViewSet from rest_framework import mixins @@ -35,6 +37,8 @@ from .serializers import RepositoryAuthorizationSerializer from .serializers import RequestRepositoryAuthorizationSerializer from .serializers import RepositoryExampleSerializer +from .serializers import AnalyzeTextSerializer +from .serializers import EvaluateSerializer from .permissions import RepositoryPermission from .permissions import RepositoryAdminManagerAuthorization from .permissions import RepositoryExamplePermission @@ -54,6 +58,7 @@ class RepositoryViewSet( """ queryset = Repository.objects lookup_field = 'uuid' + lookup_fields = ['uuid'] serializer_class = RepositorySerializer permission_classes = [ IsAuthenticatedOrReadOnly, @@ -61,6 +66,115 @@ class RepositoryViewSet( ] metadata_class = Metadata + @action( + detail=True, + methods=['GET'], + url_name='repository-languages-status', + lookup_fields=['uuid']) + def languagesstatus(self, request, **kwargs): + """ + Get current language status. + """ + if self.lookup_field not in kwargs: + return Response(status=405) + + repository = self.get_object() + return Response({ + 'languages_status': repository.languages_status, + }) + + @action( + detail=True, + methods=['GET'], + url_name='repository-train', + lookup_fields=['uuid']) + def train(self, request, **kwargs): + """ + Train current update using Bothub NLP service + """ + if self.lookup_field not in kwargs: + return Response({}, status=403) + repository = self.get_object() + user_authorization = repository.get_user_authorization(request.user) + if not user_authorization.can_write: + raise PermissionDenied() + request = Repository.request_nlp_train( # pragma: no cover + user_authorization) + if request.status_code != status.HTTP_200_OK: # pragma: no cover + raise APIException( # pragma: no cover + {'status_code': request.status_code}, + code=request.status_code) + return Response(request.json()) # pragma: no cover + + @action( + detail=True, + methods=['POST'], + url_name='repository-analyze', + permission_classes=[], + lookup_fields=['uuid']) + def analyze(self, request, **kwargs): + repository = self.get_object() + user_authorization = repository.get_user_authorization(request.user) + serializer = AnalyzeTextSerializer( + data=request.data) # pragma: no cover + serializer.is_valid(raise_exception=True) # pragma: no cover + request = Repository.request_nlp_analyze( + user_authorization, + serializer.data) # pragma: no cover + + if request.status_code == status.HTTP_200_OK: # pragma: no cover + return Response(request.json()) # pragma: no cover + + response = None # pragma: no cover + try: # pragma: no cover + response = request.json() # pragma: no cover + except Exception: + pass + + if not response: # pragma: no cover + raise APIException( # pragma: no cover + detail=_('Something unexpected happened! ' + \ + 'We couldn\'t analyze your text.')) + error = response.get('error') # pragma: no cover + message = error.get('message') # pragma: no cover + raise APIException(detail=message) # pragma: no cover + + @action( + detail=True, + methods=['POST'], + url_name='repository-evaluate', + lookup_fields=['uuid']) + def evaluate(self, request, **kwargs): + """ + Evaluate repository using Bothub NLP service + """ + repository = self.get_object() + user_authorization = repository.get_user_authorization(request.user) + if not user_authorization.can_write: + raise PermissionDenied() + serializer = EvaluateSerializer( + data=request.data) # pragma: no cover + serializer.is_valid(raise_exception=True) # pragma: no cover + + if not repository.evaluations( + language=request.data.get('language')).count(): + raise APIException( + detail=_('You need to have at least ' + + 'one registered test phrase')) # pragma: no cover + + if len(repository.intents) <= 1: + raise APIException( + detail=_('You need to have at least ' + + 'two registered intents')) # pragma: no cover + + request = Repository.request_nlp_evaluate( # pragma: no cover + user_authorization, serializer.data) + if request.status_code != status.HTTP_200_OK: # pragma: no cover + raise APIException( # pragma: no cover + {'status_code': request.status_code}, + code=request.status_code) + return Response(request.json()) # pragma: no cover + @method_decorator( name='list', diff --git a/bothub/api/v2/tests/test_repository.py b/bothub/api/v2/tests/test_repository.py index 0a5ccbcb..e86b678a 100644 --- a/bothub/api/v2/tests/test_repository.py +++ b/bothub/api/v2/tests/test_repository.py @@ -1925,3 +1925,251 @@ def test_intent_with_special_char(self): self.assertEqual( len(content_data.get('intent')), 1) + + +class RetrieveRepositoryTestCase(TestCase): + def setUp(self): + self.factory = RequestFactory() + + self.owner, self.owner_token = create_user_and_token('owner') + self.user, self.user_token = create_user_and_token() + + self.repository = Repository.objects.create( + owner=self.owner, + name='Testing', + slug='test', + language=languages.LANGUAGE_EN) + + self.private_repository = Repository.objects.create( + owner=self.owner, + name='Testing Private', + slug='private', + language=languages.LANGUAGE_EN, + is_private=True) + + def request(self, repository, token): + authorization_header = { + 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), + } + request = self.factory.get( + '/v2/repository/repository/{}/'.format( + str(repository.uuid)), + **authorization_header) + response = RepositoryViewSet.as_view( + {'get': 'retrieve'})( + request, + uuid=repository.uuid) + response.render() + content_data = json.loads(response.content) + return (response, content_data,) + + def test_allowed_in_public(self): + # owner + response, content_data = self.request( + self.repository, + self.owner_token) + self.assertEqual( + response.status_code, + status.HTTP_200_OK) + # secondary user + response, content_data = self.request( + self.repository, + self.user_token) + self.assertEqual( + response.status_code, + status.HTTP_200_OK) + + def test_allowed_in_private(self): + # owner + response, content_data = self.request( + self.private_repository, + self.owner_token) + self.assertEqual( + response.status_code, + status.HTTP_200_OK) + + def test_forbidden_in_private(self): + # secondary user + response, content_data = self.request( + self.private_repository, + self.user_token) + self.assertEqual( + response.status_code, + status.HTTP_403_FORBIDDEN) + + def test_languages_status(self): + authorization_header = { + 'HTTP_AUTHORIZATION': 'Token {}'.format(self.user_token.key), + } + request = self.factory.get( + '/v2/repository/repository/{}/languagesstatus/'.format( + self.repository.uuid), + **authorization_header) + response = RepositoryViewSet.as_view( + {'get': 'languagesstatus'})( + request, + uuid=self.repository.uuid) + self.assertEqual( + response.status_code, + status.HTTP_200_OK) + + def test_available_request_authorization(self): + response, content_data = self.request( + self.repository, + self.user_token) + self.assertTrue(content_data.get('available_request_authorization')) + + def test_owner_not_available_request_authorization(self): + response, content_data = self.request( + self.repository, + self.owner_token) + self.assertFalse(content_data.get('available_request_authorization')) + + def test_user_not_available_request_authorization(self): + authorization = self.repository.get_user_authorization(self.user) + authorization.role = RepositoryAuthorization.ROLE_USER + authorization.save() + response, content_data = self.request( + self.repository, + self.user_token) + self.assertFalse(content_data.get('available_request_authorization')) + + def test_requested_not_available_request_authorization(self): + RequestRepositoryAuthorization.objects.create( + user=self.user, + repository=self.repository, + text='I can contribute') + response, content_data = self.request( + self.repository, + self.user_token) + self.assertFalse(content_data.get('available_request_authorization')) + + def test_none_request_authorization(self): + response, content_data = self.request( + self.repository, + self.user_token) + self.assertIsNone(content_data.get('request_authorization')) + + def test_request_authorization(self): + text = 'I can contribute' + request = RequestRepositoryAuthorization.objects.create( + user=self.user, + repository=self.repository, + text=text) + response, content_data = self.request( + self.repository, + self.user_token) + request_authorization = content_data.get('request_authorization') + self.assertEqual( + request_authorization.get('id'), + request.id) + self.assertEqual( + request_authorization.get('text'), + text) + + +class TrainRepositoryTestCase(TestCase): + def setUp(self): + self.factory = RequestFactory() + + self.owner, self.owner_token = create_user_and_token('owner') + self.user, self.user_token = create_user_and_token() + + self.repository = Repository.objects.create( + owner=self.owner, + name='Testing', + slug='test', + language=languages.LANGUAGE_EN) + + def request(self, repository, token): + authorization_header = { + 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), + } + request = self.factory.get( + '/v2/repository/repository/{}/train/'.format( + str(repository.uuid)), + **authorization_header) + response = RepositoryViewSet.as_view({'get': 'train'})(request) + response.render() + content_data = json.loads(response.content) + return (response, content_data,) + + def test_permission_denied(self): + response, content_data = self.request(self.repository, self.user_token) + self.assertEqual( + response.status_code, + status.HTTP_403_FORBIDDEN) + + +class AnalyzeRepositoryTestCase(TestCase): + def setUp(self): + self.factory = RequestFactory() + + self.owner, self.owner_token = create_user_and_token('owner') + self.user, self.user_token = create_user_and_token() + + self.repository = Repository.objects.create( + owner=self.owner, + name='Testing', + slug='test', + language=languages.LANGUAGE_EN) + self.private_repository = Repository.objects.create( + owner=self.owner, + name='Testing', + slug='private', + language=languages.LANGUAGE_EN, + is_private=True) + + def request(self, repository, token, data): + authorization_header = { + 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), + } + request = self.factory.post( + '/v2/repository/repository/{}/analyze/'.format( + str(repository.uuid)), + data, + **authorization_header) + response = RepositoryViewSet.as_view({'post': 'analyze'})( + request, + uuid=repository.uuid) + response.render() + content_data = json.loads(response.content) + return (response, content_data,) + + def test_permission_denied_in_private_repository(self): + response, content_data = self.request( + self.private_repository, + self.user_token, + { + 'language': 'en', + 'text': 'My name is Douglas', + }) + self.assertEqual( + response.status_code, + status.HTTP_403_FORBIDDEN) + + def test_language_required(self): + response, content_data = self.request( + self.repository, + self.owner_token, + { + 'language': '', + 'text': 'My name is Douglas', + }) + self.assertEqual( + response.status_code, + status.HTTP_400_BAD_REQUEST) + self.assertIn('language', content_data.keys()) + + def test_text_required(self): + response, content_data = self.request( + self.repository, + self.owner_token, + { + 'language': 'en', + 'text': '', + }) + self.assertEqual( + response.status_code, + status.HTTP_400_BAD_REQUEST) + self.assertIn('text', content_data.keys()) From 660c6766f8aa11f82bdae82412d12df909e88c32 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Thu, 15 Aug 2019 16:13:14 -0300 Subject: [PATCH 119/207] [fix] Datetime field metadata --- bothub/api/v2/metadata.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bothub/api/v2/metadata.py b/bothub/api/v2/metadata.py index 7b431c55..24ffd14d 100644 --- a/bothub/api/v2/metadata.py +++ b/bothub/api/v2/metadata.py @@ -25,7 +25,7 @@ class Metadata(BaseMetadata): serializers.FloatField: 'float', serializers.DecimalField: 'decimal', serializers.DateField: 'date', - serializers.DateTimeField: 'datetime', + serializers.DateTimeField: 'date', serializers.TimeField: 'time', serializers.ChoiceField: 'choice', serializers.MultipleChoiceField: 'multiple choice', From 8dec138f1b7a8dfa1f92430555eb41c5c1327689 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Thu, 15 Aug 2019 16:18:26 -0300 Subject: [PATCH 120/207] [fix] PEP8 --- bothub/api/v2/repository/views.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bothub/api/v2/repository/views.py b/bothub/api/v2/repository/views.py index acda6de9..241ce0b1 100644 --- a/bothub/api/v2/repository/views.py +++ b/bothub/api/v2/repository/views.py @@ -157,7 +157,8 @@ def evaluate(self, request, **kwargs): serializer.is_valid(raise_exception=True) # pragma: no cover if not repository.evaluations( - language=request.data.get('language')).count(): + language=request.data.get('language') + ).count(): raise APIException( detail=_('You need to have at least ' + 'one registered test phrase')) # pragma: no cover From 76f24232744f4196d5c51af98fca64de0dc36bc9 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Thu, 15 Aug 2019 16:34:15 -0300 Subject: [PATCH 121/207] Added method_decorator deprecated swagger --- bothub/api/v1/views.py | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/bothub/api/v1/views.py b/bothub/api/v1/views.py index 334744ea..caf3cf8b 100644 --- a/bothub/api/v1/views.py +++ b/bothub/api/v1/views.py @@ -384,6 +384,12 @@ def get_object(self): # ViewSets +@method_decorator( + name='create', + decorator=swagger_auto_schema( + deprecated=True + ) +) class NewRepositoryViewSet( mixins.CreateModelMixin, GenericViewSet): @@ -444,6 +450,30 @@ def get_queryset(self, *args, **kwargs): return self.queryset.none() +@method_decorator( + name='retrieve', + decorator=swagger_auto_schema( + deprecated=True + ) +) +@method_decorator( + name='update', + decorator=swagger_auto_schema( + deprecated=True + ) +) +@method_decorator( + name='partial_update', + decorator=swagger_auto_schema( + deprecated=True + ) +) +@method_decorator( + name='destroy', + decorator=swagger_auto_schema( + deprecated=True + ) +) class RepositoryViewSet( MultipleFieldLookupMixin, mixins.RetrieveModelMixin, From 08c412df23284b7bba3838e3086404bc2dd9b7e8 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Thu, 15 Aug 2019 16:42:18 -0300 Subject: [PATCH 122/207] Updated routers name --- bothub/api/v2/routers.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bothub/api/v2/routers.py b/bothub/api/v2/routers.py index 6b40fd6c..76d1a2a6 100644 --- a/bothub/api/v2/routers.py +++ b/bothub/api/v2/routers.py @@ -108,8 +108,9 @@ def get_lookup_regex(self, viewset, lookup_prefix=''): RepositoryAuthorizationRequestsViewSet ) router.register('repository/example', RepositoryExampleViewSet) -router.register('evaluate/results', ResultsListViewSet) -router.register('evaluate', EvaluateViewSet) +router.register('repository/evaluate/results', ResultsListViewSet) +router.register('repository/evaluate', EvaluateViewSet) +router.register('repository/translation', RepositoryTranslatedExampleViewSet) router.register('account/login', LoginViewSet) router.register('account/register', RegisterUserViewSet) router.register('account/change-password', ChangePasswordViewSet) @@ -117,4 +118,3 @@ def get_lookup_regex(self, viewset, lookup_prefix=''): router.register('account/user-profile', UserProfileViewSet) router.register('account/search-user', SearchUserViewSet) router.register('account/reset-password', ResetPasswordViewSet) -router.register('translation', RepositoryTranslatedExampleViewSet) From ad03f03353fd4aabeb9cc51317ae51f4cf4d7c03 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Fri, 16 Aug 2019 10:06:07 -0300 Subject: [PATCH 123/207] Added Serializer Votes in ShortRepository --- bothub/api/v2/repository/serializers.py | 55 ++++++++++++++----------- 1 file changed, 30 insertions(+), 25 deletions(-) diff --git a/bothub/api/v2/repository/serializers.py b/bothub/api/v2/repository/serializers.py index 2e4a2f0e..00e76a02 100644 --- a/bothub/api/v2/repository/serializers.py +++ b/bothub/api/v2/repository/serializers.py @@ -312,6 +312,31 @@ def get_available_request_authorization(self, obj): return True +class RepositoryVotesSerializer(serializers.ModelSerializer): + class Meta: + model = RepositoryVote + fields = [ + 'user', + 'repository', + 'created', + ] + + read_only_fields = [ + 'user', + 'created_at', + ] + ref_name = None + + def create(self, validated_data): + user = self.context.get('request').user + repository = validated_data.pop('repository') + vote, created = RepositoryVote.objects.get_or_create( + repository=repository, + user=user + ) + return vote + + class ShortRepositorySerializer(serializers.ModelSerializer): class Meta: model = Repository @@ -329,6 +354,7 @@ class Meta: 'owner', 'owner__nickname', 'absolute_url', + 'votes', ] read_only = fields ref_name = None @@ -347,35 +373,14 @@ class Meta: read_only=True) absolute_url = serializers.SerializerMethodField() + votes = RepositoryVotesSerializer( + many=True, + read_only=True) + def get_absolute_url(self, obj): return obj.get_absolute_url() -class RepositoryVotesSerializer(serializers.ModelSerializer): - class Meta: - model = RepositoryVote - fields = [ - 'user', - 'repository', - 'created', - ] - - read_only_fields = [ - 'user', - 'created_at', - ] - ref_name = None - - def create(self, validated_data): - user = self.context.get('request').user - repository = validated_data.pop('repository') - vote, created = RepositoryVote.objects.get_or_create( - repository=repository, - user=user - ) - return vote - - class RepositoryContributionsSerializer(serializers.ModelSerializer): class Meta: model = RepositoryAuthorization From aff0f1c0199175f8e1481e673589d5c314003aef Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Fri, 16 Aug 2019 13:40:32 -0300 Subject: [PATCH 124/207] [fix] Migrations --- .../0032_repository_total_updates.py | 31 +++++++++++++++++++ ...702_1419.py => 0033_auto_20190702_1419.py} | 2 +- ...702_1443.py => 0034_auto_20190702_1443.py} | 2 +- bothub/common/models.py | 11 ++++++- bothub/common/tests.py | 1 + 5 files changed, 44 insertions(+), 3 deletions(-) create mode 100644 bothub/common/migrations/0032_repository_total_updates.py rename bothub/common/migrations/{0032_auto_20190702_1419.py => 0033_auto_20190702_1419.py} (91%) rename bothub/common/migrations/{0033_auto_20190702_1443.py => 0034_auto_20190702_1443.py} (88%) diff --git a/bothub/common/migrations/0032_repository_total_updates.py b/bothub/common/migrations/0032_repository_total_updates.py new file mode 100644 index 00000000..77b7f9ab --- /dev/null +++ b/bothub/common/migrations/0032_repository_total_updates.py @@ -0,0 +1,31 @@ +# Generated by Django 2.1.5 on 2019-08-14 19:45 + +from django.db import migrations, models + +from bothub.common.models import RepositoryUpdate +from bothub.common.models import Repository + + +def updateRepository(apps, schema_editor): + for update in RepositoryUpdate.objects.all().filter( + trained_at__isnull=False + ): + repository = Repository.objects.get(uuid=update.repository.uuid) + repository.total_updates += 1 + repository.save() + + +class Migration(migrations.Migration): + + dependencies = [ + ('common', '0031_auto_20190502_1732'), + ] + + operations = [ + migrations.AddField( + model_name='repository', + name='total_updates', + field=models.IntegerField(default=0, verbose_name='total updates'), + ), + migrations.RunPython(updateRepository), + ] diff --git a/bothub/common/migrations/0032_auto_20190702_1419.py b/bothub/common/migrations/0033_auto_20190702_1419.py similarity index 91% rename from bothub/common/migrations/0032_auto_20190702_1419.py rename to bothub/common/migrations/0033_auto_20190702_1419.py index a1d0a178..8d0b1a20 100644 --- a/bothub/common/migrations/0032_auto_20190702_1419.py +++ b/bothub/common/migrations/0033_auto_20190702_1419.py @@ -7,7 +7,7 @@ class Migration(migrations.Migration): dependencies = [ - ('common', '0031_auto_20190502_1732'), + ('common', '0032_repository_total_updates'), ] operations = [ diff --git a/bothub/common/migrations/0033_auto_20190702_1443.py b/bothub/common/migrations/0034_auto_20190702_1443.py similarity index 88% rename from bothub/common/migrations/0033_auto_20190702_1443.py rename to bothub/common/migrations/0034_auto_20190702_1443.py index 1d969c29..94f28b53 100644 --- a/bothub/common/migrations/0033_auto_20190702_1443.py +++ b/bothub/common/migrations/0034_auto_20190702_1443.py @@ -6,7 +6,7 @@ class Migration(migrations.Migration): dependencies = [ - ('common', '0032_auto_20190702_1419'), + ('common', '0033_auto_20190702_1419'), ] operations = [ diff --git a/bothub/common/models.py b/bothub/common/models.py index 70f60ffa..176a5675 100644 --- a/bothub/common/models.py +++ b/bothub/common/models.py @@ -62,7 +62,7 @@ def publics(self): def order_by_relevance(self): return self \ .annotate(examples_sum=models.Sum('updates__added')) \ - .order_by('-examples_sum', '-created_at') + .order_by('-total_updates', '-examples_sum', '-created_at') def supported_language(self, language): valid_examples = RepositoryExample.objects.filter( @@ -176,6 +176,13 @@ class Meta: _('created at'), auto_now_add=True) + total_updates = models.IntegerField( + _('total updates'), + default=0, + blank=False, + null=False + ) + objects = RepositoryManager() nlp_train_url = '{}train/'.format(settings.BOTHUB_NLP_BASE_URL) @@ -642,6 +649,8 @@ def save_training(self, bot_data): self.trained_at = timezone.now() self.bot_data = base64.b64encode(bot_data).decode('utf8') + self.repository.total_updates += 1 + self.repository.save() self.save( update_fields=[ 'trained_at', diff --git a/bothub/common/tests.py b/bothub/common/tests.py index b88521df..02d9e2a4 100644 --- a/bothub/common/tests.py +++ b/bothub/common/tests.py @@ -290,6 +290,7 @@ def test_last_trained_update(self): self.assertEqual( update_1, self.repository.last_trained_update()) + self.assertEqual(self.repository.total_updates, 1) def test_available_languages(self): available_languages = self.repository.available_languages From 67c02b830bb640a95db23caa49981bf8e4cb11a8 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Fri, 16 Aug 2019 17:32:21 -0300 Subject: [PATCH 125/207] [fix] Migrations --- ...0702_1419.py => 0033_auto_20190816_2030.py} | 7 ++++--- .../migrations/0034_auto_20190702_1443.py | 18 ------------------ 2 files changed, 4 insertions(+), 21 deletions(-) rename bothub/common/migrations/{0033_auto_20190702_1419.py => 0033_auto_20190816_2030.py} (66%) delete mode 100644 bothub/common/migrations/0034_auto_20190702_1443.py diff --git a/bothub/common/migrations/0033_auto_20190702_1419.py b/bothub/common/migrations/0033_auto_20190816_2030.py similarity index 66% rename from bothub/common/migrations/0033_auto_20190702_1419.py rename to bothub/common/migrations/0033_auto_20190816_2030.py index 8d0b1a20..f6de4417 100644 --- a/bothub/common/migrations/0033_auto_20190702_1419.py +++ b/bothub/common/migrations/0033_auto_20190816_2030.py @@ -1,7 +1,7 @@ -# Generated by Django 2.1.5 on 2019-07-02 14:19 +# Generated by Django 2.1.5 on 2019-08-16 20:30 from django.db import migrations, models -import django.utils.datetime_safe +import django.utils.timezone class Migration(migrations.Migration): @@ -18,6 +18,7 @@ class Migration(migrations.Migration): migrations.AddField( model_name='repositoryvote', name='created', - field=models.DateTimeField(default=django.utils.datetime_safe.datetime.now, editable=False), + field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now), + preserve_default=False, ), ] diff --git a/bothub/common/migrations/0034_auto_20190702_1443.py b/bothub/common/migrations/0034_auto_20190702_1443.py deleted file mode 100644 index 94f28b53..00000000 --- a/bothub/common/migrations/0034_auto_20190702_1443.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 2.1.5 on 2019-07-02 14:43 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('common', '0033_auto_20190702_1419'), - ] - - operations = [ - migrations.AlterField( - model_name='repositoryvote', - name='created', - field=models.DateTimeField(auto_now_add=True), - ), - ] From 7da19d2f6c674eca82b1a0649ab17e25ef893ee7 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Fri, 16 Aug 2019 17:34:57 -0300 Subject: [PATCH 126/207] [fix] Migrations --- bothub/common/migrations/0033_auto_20190816_2030.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/bothub/common/migrations/0033_auto_20190816_2030.py b/bothub/common/migrations/0033_auto_20190816_2030.py index f6de4417..0196b4a4 100644 --- a/bothub/common/migrations/0033_auto_20190816_2030.py +++ b/bothub/common/migrations/0033_auto_20190816_2030.py @@ -11,10 +11,6 @@ class Migration(migrations.Migration): ] operations = [ - migrations.RemoveField( - model_name='repositoryvote', - name='vote', - ), migrations.AddField( model_name='repositoryvote', name='created', From 0587d04e515e5230cccb3ab885495550c0b3caea Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Fri, 16 Aug 2019 17:50:24 -0300 Subject: [PATCH 127/207] [fix] Migrations --- bothub/common/migrations/0033_auto_20190816_2030.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/bothub/common/migrations/0033_auto_20190816_2030.py b/bothub/common/migrations/0033_auto_20190816_2030.py index 0196b4a4..f6de4417 100644 --- a/bothub/common/migrations/0033_auto_20190816_2030.py +++ b/bothub/common/migrations/0033_auto_20190816_2030.py @@ -11,6 +11,10 @@ class Migration(migrations.Migration): ] operations = [ + migrations.RemoveField( + model_name='repositoryvote', + name='vote', + ), migrations.AddField( model_name='repositoryvote', name='created', From 6b59be9c4f7f30e022040cbf21f038c5f295a316 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Tue, 20 Aug 2019 12:08:01 -0300 Subject: [PATCH 128/207] Added router nlp --- bothub/api/v2/nlp/__init__.py | 0 bothub/api/v2/nlp/views.py | 31 +++++++++++++++++++++++++++++++ bothub/api/v2/routers.py | 5 +++++ 3 files changed, 36 insertions(+) create mode 100644 bothub/api/v2/nlp/__init__.py create mode 100644 bothub/api/v2/nlp/views.py diff --git a/bothub/api/v2/nlp/__init__.py b/bothub/api/v2/nlp/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/bothub/api/v2/nlp/views.py b/bothub/api/v2/nlp/views.py new file mode 100644 index 00000000..fbec481b --- /dev/null +++ b/bothub/api/v2/nlp/views.py @@ -0,0 +1,31 @@ +from rest_framework import mixins +from rest_framework.response import Response +from rest_framework.viewsets import GenericViewSet +from rest_framework.permissions import AllowAny + +from bothub.common.models import RepositoryAuthorization + + +class RepositoryAuthorizationNLPViewSet( + mixins.RetrieveModelMixin, + GenericViewSet): + queryset = RepositoryAuthorization.objects + permission_classes = [AllowAny] + + def retrieve(self, request, *args, **kwargs): + repository_authorization = self.get_object() + current_update = repository_authorization.repository.current_update( + str(request.query_params.get('language')) + ) + + data = { + 'ready_for_train': + current_update.ready_for_train, + 'current_update_id': + current_update.id, + 'repository_authorization_user_id': + repository_authorization.user.id, + 'language': + current_update.language + } + return Response(data) diff --git a/bothub/api/v2/routers.py b/bothub/api/v2/routers.py index 7fe51b45..09b78725 100644 --- a/bothub/api/v2/routers.py +++ b/bothub/api/v2/routers.py @@ -10,6 +10,7 @@ from .repository.views import RepositoryAuthorizationRequestsViewSet from .repository.views import RepositoryExampleViewSet from .repository.views import RepositoryUpdatesViewSet +from .nlp.views import RepositoryAuthorizationNLPViewSet from .examples.views import ExamplesViewSet from .evaluate.views import EvaluateViewSet from .evaluate.views import ResultsListViewSet @@ -113,6 +114,10 @@ def get_lookup_regex(self, viewset, lookup_prefix=''): router.register('repository/evaluate', EvaluateViewSet) router.register('repository/translation', RepositoryTranslatedExampleViewSet) router.register('repository/updates', RepositoryUpdatesViewSet) +router.register( + 'repository/nlp/authorization', + RepositoryAuthorizationNLPViewSet +) router.register('account/login', LoginViewSet) router.register('account/register', RegisterUserViewSet) router.register('account/change-password', ChangePasswordViewSet) From 19d1263a24a83a6878494549bd70f33e6c0a4aa2 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Tue, 20 Aug 2019 13:57:45 -0300 Subject: [PATCH 129/207] Added router nlp parse --- bothub/api/v2/nlp/views.py | 22 +++++++++++++++++++++- bothub/api/v2/routers.py | 11 ++++++++--- 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/bothub/api/v2/nlp/views.py b/bothub/api/v2/nlp/views.py index fbec481b..132da09e 100644 --- a/bothub/api/v2/nlp/views.py +++ b/bothub/api/v2/nlp/views.py @@ -6,7 +6,7 @@ from bothub.common.models import RepositoryAuthorization -class RepositoryAuthorizationNLPViewSet( +class RepositoryAuthorizationTrainViewSet( mixins.RetrieveModelMixin, GenericViewSet): queryset = RepositoryAuthorization.objects @@ -29,3 +29,23 @@ def retrieve(self, request, *args, **kwargs): current_update.language } return Response(data) + + +class RepositoryAuthorizationParseViewSet( + mixins.RetrieveModelMixin, + GenericViewSet): + queryset = RepositoryAuthorization.objects + permission_classes = [AllowAny] + + def retrieve(self, request, *args, **kwargs): + repository_authorization = self.get_object() + repository = repository_authorization.repository + update = repository.last_trained_update( + str(request.query_params.get('language')) + ) + data = { + 'update': False if update is None else True, + 'update_id': update.id, + 'language': update.language + } + return Response(data) diff --git a/bothub/api/v2/routers.py b/bothub/api/v2/routers.py index 09b78725..059ccc1e 100644 --- a/bothub/api/v2/routers.py +++ b/bothub/api/v2/routers.py @@ -10,7 +10,8 @@ from .repository.views import RepositoryAuthorizationRequestsViewSet from .repository.views import RepositoryExampleViewSet from .repository.views import RepositoryUpdatesViewSet -from .nlp.views import RepositoryAuthorizationNLPViewSet +from .nlp.views import RepositoryAuthorizationTrainViewSet +from .nlp.views import RepositoryAuthorizationParseViewSet from .examples.views import ExamplesViewSet from .evaluate.views import EvaluateViewSet from .evaluate.views import ResultsListViewSet @@ -115,8 +116,12 @@ def get_lookup_regex(self, viewset, lookup_prefix=''): router.register('repository/translation', RepositoryTranslatedExampleViewSet) router.register('repository/updates', RepositoryUpdatesViewSet) router.register( - 'repository/nlp/authorization', - RepositoryAuthorizationNLPViewSet + 'repository/nlp/authorization/train', + RepositoryAuthorizationTrainViewSet +) +router.register( + 'repository/nlp/authorization/parse', + RepositoryAuthorizationParseViewSet ) router.register('account/login', LoginViewSet) router.register('account/register', RegisterUserViewSet) From cdf167b36f80561575c970f5bb62856eef26e3e0 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Tue, 20 Aug 2019 14:06:21 -0300 Subject: [PATCH 130/207] Added router info nlp --- bothub/api/v2/nlp/views.py | 14 ++++++++++++++ bothub/api/v2/routers.py | 5 +++++ 2 files changed, 19 insertions(+) diff --git a/bothub/api/v2/nlp/views.py b/bothub/api/v2/nlp/views.py index 132da09e..21af1890 100644 --- a/bothub/api/v2/nlp/views.py +++ b/bothub/api/v2/nlp/views.py @@ -3,6 +3,7 @@ from rest_framework.viewsets import GenericViewSet from rest_framework.permissions import AllowAny +from bothub.api.v2.repository.serializers import RepositorySerializer from bothub.common.models import RepositoryAuthorization @@ -49,3 +50,16 @@ def retrieve(self, request, *args, **kwargs): 'language': update.language } return Response(data) + + +class RepositoryAuthorizationInfoViewSet( + mixins.RetrieveModelMixin, + GenericViewSet): + queryset = RepositoryAuthorization.objects + permission_classes = [AllowAny] + + def retrieve(self, request, *args, **kwargs): + repository_authorization = self.get_object() + repository = repository_authorization.repository + serializer = RepositorySerializer(repository) + return Response(serializer.data) diff --git a/bothub/api/v2/routers.py b/bothub/api/v2/routers.py index 059ccc1e..e517ff83 100644 --- a/bothub/api/v2/routers.py +++ b/bothub/api/v2/routers.py @@ -12,6 +12,7 @@ from .repository.views import RepositoryUpdatesViewSet from .nlp.views import RepositoryAuthorizationTrainViewSet from .nlp.views import RepositoryAuthorizationParseViewSet +from .nlp.views import RepositoryAuthorizationInfoViewSet from .examples.views import ExamplesViewSet from .evaluate.views import EvaluateViewSet from .evaluate.views import ResultsListViewSet @@ -123,6 +124,10 @@ def get_lookup_regex(self, viewset, lookup_prefix=''): 'repository/nlp/authorization/parse', RepositoryAuthorizationParseViewSet ) +router.register( + 'repository/nlp/authorization/info', + RepositoryAuthorizationInfoViewSet +) router.register('account/login', LoginViewSet) router.register('account/register', RegisterUserViewSet) router.register('account/change-password', ChangePasswordViewSet) From e02698761b31df61896b7b3e4837e854e5401cfc Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Tue, 20 Aug 2019 14:24:50 -0300 Subject: [PATCH 131/207] Added router evaluate --- bothub/api/v2/nlp/views.py | 21 +++++++++++++++++++++ bothub/api/v2/routers.py | 5 +++++ 2 files changed, 26 insertions(+) diff --git a/bothub/api/v2/nlp/views.py b/bothub/api/v2/nlp/views.py index 21af1890..00dfe8bf 100644 --- a/bothub/api/v2/nlp/views.py +++ b/bothub/api/v2/nlp/views.py @@ -63,3 +63,24 @@ def retrieve(self, request, *args, **kwargs): repository = repository_authorization.repository serializer = RepositorySerializer(repository) return Response(serializer.data) + + +class RepositoryAuthorizationEvaluateViewSet( + mixins.RetrieveModelMixin, + GenericViewSet): + queryset = RepositoryAuthorization.objects + permission_classes = [AllowAny] + + def retrieve(self, request, *args, **kwargs): + repository_authorization = self.get_object() + repository = repository_authorization.repository + update = repository.last_trained_update( + str(request.query_params.get('language')) + ) + data = { + 'update': False if update is None else True, + 'update_id': update.id, + 'language': update.language, + 'user_id': repository_authorization.user.id + } + return Response(data) diff --git a/bothub/api/v2/routers.py b/bothub/api/v2/routers.py index e517ff83..8242fdea 100644 --- a/bothub/api/v2/routers.py +++ b/bothub/api/v2/routers.py @@ -13,6 +13,7 @@ from .nlp.views import RepositoryAuthorizationTrainViewSet from .nlp.views import RepositoryAuthorizationParseViewSet from .nlp.views import RepositoryAuthorizationInfoViewSet +from .nlp.views import RepositoryAuthorizationEvaluateViewSet from .examples.views import ExamplesViewSet from .evaluate.views import EvaluateViewSet from .evaluate.views import ResultsListViewSet @@ -128,6 +129,10 @@ def get_lookup_regex(self, viewset, lookup_prefix=''): 'repository/nlp/authorization/info', RepositoryAuthorizationInfoViewSet ) +router.register( + 'repository/nlp/authorization/evaluate', + RepositoryAuthorizationEvaluateViewSet +) router.register('account/login', LoginViewSet) router.register('account/register', RegisterUserViewSet) router.register('account/change-password', ChangePasswordViewSet) From c215d81974ac68c695e2f94dc205c34610654b75 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Tue, 20 Aug 2019 14:39:57 -0300 Subject: [PATCH 132/207] Added router langs nlp --- bothub/api/v2/nlp/views.py | 29 +++++++++++++++++++++++++++++ bothub/api/v2/routers.py | 5 +++++ 2 files changed, 34 insertions(+) diff --git a/bothub/api/v2/nlp/views.py b/bothub/api/v2/nlp/views.py index 00dfe8bf..a1edd937 100644 --- a/bothub/api/v2/nlp/views.py +++ b/bothub/api/v2/nlp/views.py @@ -5,6 +5,7 @@ from bothub.api.v2.repository.serializers import RepositorySerializer from bothub.common.models import RepositoryAuthorization +from bothub.common import languages class RepositoryAuthorizationTrainViewSet( @@ -84,3 +85,31 @@ def retrieve(self, request, *args, **kwargs): 'user_id': repository_authorization.user.id } return Response(data) + + +class NLPLangsViewSet( + mixins.ListModelMixin, + GenericViewSet): + queryset = RepositoryAuthorization.objects + permission_classes = [AllowAny] + + def list(self, request, *args, **kwargs): + data = { + 'english': [ + languages.LANGUAGE_EN, + ], + 'portuguese': [ + languages.LANGUAGE_PT, + languages.LANGUAGE_PT_BR, + ], + languages.LANGUAGE_PT: [ + languages.LANGUAGE_PT_BR, + ], + 'pt-br': [ + languages.LANGUAGE_PT_BR, + ], + 'br': [ + languages.LANGUAGE_PT_BR, + ], + } + return Response(data) diff --git a/bothub/api/v2/routers.py b/bothub/api/v2/routers.py index 8242fdea..a163c8fa 100644 --- a/bothub/api/v2/routers.py +++ b/bothub/api/v2/routers.py @@ -14,6 +14,7 @@ from .nlp.views import RepositoryAuthorizationParseViewSet from .nlp.views import RepositoryAuthorizationInfoViewSet from .nlp.views import RepositoryAuthorizationEvaluateViewSet +from .nlp.views import NLPLangsViewSet from .examples.views import ExamplesViewSet from .evaluate.views import EvaluateViewSet from .evaluate.views import ResultsListViewSet @@ -133,6 +134,10 @@ def get_lookup_regex(self, viewset, lookup_prefix=''): 'repository/nlp/authorization/evaluate', RepositoryAuthorizationEvaluateViewSet ) +router.register( + 'repository/nlp/authorization/langs', + NLPLangsViewSet +) router.register('account/login', LoginViewSet) router.register('account/register', RegisterUserViewSet) router.register('account/change-password', ChangePasswordViewSet) From d90d571b66a547e613177818addd6b238ef11183 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Wed, 21 Aug 2019 14:15:01 -0300 Subject: [PATCH 133/207] Added routers train nlp_nlu --- bothub/api/v2/nlp/views.py | 177 +++++++++++++++++++++++++++++++++++++ bothub/api/v2/routers.py | 5 ++ 2 files changed, 182 insertions(+) diff --git a/bothub/api/v2/nlp/views.py b/bothub/api/v2/nlp/views.py index a1edd937..43b8d711 100644 --- a/bothub/api/v2/nlp/views.py +++ b/bothub/api/v2/nlp/views.py @@ -1,15 +1,22 @@ +import base64 +from django.db import models from rest_framework import mixins +from rest_framework.decorators import action from rest_framework.response import Response from rest_framework.viewsets import GenericViewSet from rest_framework.permissions import AllowAny from bothub.api.v2.repository.serializers import RepositorySerializer +from bothub.authentication.models import User from bothub.common.models import RepositoryAuthorization +from bothub.common.models import RepositoryUpdate +from bothub.common.models import Repository from bothub.common import languages class RepositoryAuthorizationTrainViewSet( mixins.RetrieveModelMixin, + mixins.CreateModelMixin, GenericViewSet): queryset = RepositoryAuthorization.objects permission_classes = [AllowAny] @@ -32,6 +39,153 @@ def retrieve(self, request, *args, **kwargs): } return Response(data) + @action( + detail=True, + methods=['POST'], + url_name='start_training', + lookup_field=[]) + def starttraining(self, request, **kwargs): + repository = RepositoryUpdate.objects.get( + id=request.data.get('update_id') + ) + examples = [] + for example in repository.examples: + examples.append( + { + 'example_id': example.id, + 'example_intent': example.intent + } + ) + repository.start_training( + User.objects.get(id=request.data.get('by_user')) + ) + + label_examples_query = [] + + for label_examples in repository.examples.filter( + entities__entity__label__isnull=False + ).annotate( + entities_count=models.Count('entities') + ).filter( + entities_count__gt=0): + label_examples_query.append( + { + 'example_id': label_examples.id + } + ) + + data = { + 'language': repository.language, + 'update_id': repository.id, + 'repository_uuid': str(repository.repository.uuid), + 'examples': examples, + 'label_examples_query': label_examples_query, + 'intent': repository.intents, + 'algorithm': repository.algorithm, + 'use_name_entities': repository.use_name_entities, + 'use_competing_intents': repository.use_competing_intents, + 'ALGORITHM_STATISTICAL_MODEL': + Repository.ALGORITHM_STATISTICAL_MODEL, + 'ALGORITHM_NEURAL_NETWORK_EXTERNAL': + Repository.ALGORITHM_NEURAL_NETWORK_EXTERNAL + } + return Response(data) + + @action( + detail=True, + methods=['GET'], + url_name='gettext', + lookup_field=[]) + def gettext(self, request, **kwargs): + repository = RepositoryUpdate.objects.get( + id=request.query_params.get('update_id') + ).examples.get( + id=request.query_params.get('example_id') + ).get_text( + request.query_params.get('language') + ) + + data = { + 'get_text': repository + } + return Response(data) + + @action( + detail=True, + methods=['GET'], + url_name='get_entities', + lookup_field=[]) + def getentities(self, request, **kwargs): + repository = RepositoryUpdate.objects.get( + id=request.query_params.get('update_id') + ).examples.get( + id=request.query_params.get('example_id') + ).get_entities( + request.query_params.get('language') + ) + + entities = [] + + for entit in repository: + entities.append(entit.rasa_nlu_data) + + data = { + 'entities': entities, + } + return Response(data) + + @action( + detail=True, + methods=['GET'], + url_name='get_entities_label', + lookup_field=[]) + def getentitieslabel(self, request, **kwargs): + repository = RepositoryUpdate.objects.get( + id=request.query_params.get('update_id') + ).examples.get( + id=request.query_params.get('example_id') + ).get_entities( + request.query_params.get('language') + ) + + entities = [] + + for example_entity in filter(lambda ee: ee.entity.label, repository): + entities.append( + example_entity.get_rasa_nlu_data( + label_as_entity=True + ) + ) + + data = { + 'entities': entities, + } + return Response(data) + + @action( + detail=True, + methods=['POST'], + url_name='train_fail', + lookup_field=[]) + def trainfail(self, request, **kwargs): + RepositoryUpdate.objects.get( + id=request.data.get('update_id') + ).train_fail() + return Response({}) + + @action( + detail=True, + methods=['POST'], + url_name='training_log', + lookup_field=[]) + def traininglog(self, request, **kwargs): + repository = RepositoryUpdate.objects.get( + id=request.data.get('update_id') + ) + repository.training_log = request.data.get('training_log') + repository.save(update_fields=['training_log']) + return Response({}) + class RepositoryAuthorizationParseViewSet( mixins.RetrieveModelMixin, @@ -113,3 +267,26 @@ def list(self, request, *args, **kwargs): ], } return Response(data) + + +class RepositoryUpdateInterpretersViewSet( + mixins.RetrieveModelMixin, + mixins.CreateModelMixin, + GenericViewSet): + queryset = RepositoryUpdate.objects + permission_classes = [AllowAny] + + def retrieve(self, request, *args, **kwargs): + update = self.get_object() + data = { + 'update_id': update.id, + 'repository_uuid': update.repository.uuid, + 'bot_data': str(update.bot_data) + } + return Response(data) + + def create(self, request, *args, **kwargs): + repository = self.queryset.get(pk=request.data.get('id')) + bot_data = base64.b64decode(request.data.get('bot_data')) + repository.save_training(bot_data) + return Response({}) diff --git a/bothub/api/v2/routers.py b/bothub/api/v2/routers.py index a163c8fa..dcfa2850 100644 --- a/bothub/api/v2/routers.py +++ b/bothub/api/v2/routers.py @@ -15,6 +15,7 @@ from .nlp.views import RepositoryAuthorizationInfoViewSet from .nlp.views import RepositoryAuthorizationEvaluateViewSet from .nlp.views import NLPLangsViewSet +from .nlp.views import RepositoryUpdateInterpretersViewSet from .examples.views import ExamplesViewSet from .evaluate.views import EvaluateViewSet from .evaluate.views import ResultsListViewSet @@ -138,6 +139,10 @@ def get_lookup_regex(self, viewset, lookup_prefix=''): 'repository/nlp/authorization/langs', NLPLangsViewSet ) +router.register( + 'repository/nlp/update_interpreters', + RepositoryUpdateInterpretersViewSet +) router.register('account/login', LoginViewSet) router.register('account/register', RegisterUserViewSet) router.register('account/change-password', ChangePasswordViewSet) From 08ccf3528728155f02f379d00afa2b788f2ede9a Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Fri, 23 Aug 2019 12:00:41 -0300 Subject: [PATCH 134/207] Added Routers Evaluate --- bothub/api/v2/nlp/views.py | 160 +++++++++++++++++++++++++++++++++++++ 1 file changed, 160 insertions(+) diff --git a/bothub/api/v2/nlp/views.py b/bothub/api/v2/nlp/views.py index 43b8d711..c067902a 100644 --- a/bothub/api/v2/nlp/views.py +++ b/bothub/api/v2/nlp/views.py @@ -1,4 +1,6 @@ import base64 +import json + from django.db import models from rest_framework import mixins from rest_framework.decorators import action @@ -9,6 +11,11 @@ from bothub.api.v2.repository.serializers import RepositorySerializer from bothub.authentication.models import User from bothub.common.models import RepositoryAuthorization +from bothub.common.models import RepositoryEntity +from bothub.common.models import RepositoryEvaluateResult +from bothub.common.models import RepositoryEvaluateResultScore +from bothub.common.models import RepositoryEvaluateResultIntent +from bothub.common.models import RepositoryEvaluateResultEntity from bothub.common.models import RepositoryUpdate from bothub.common.models import Repository from bothub.common import languages @@ -206,6 +213,26 @@ def retrieve(self, request, *args, **kwargs): } return Response(data) + @action( + detail=True, + methods=['GET'], + url_name='repository_entity', + lookup_field=[]) + def repositoryentity(self, request, **kwargs): + repository_update = RepositoryUpdate.objects.get( + id=request.query_params.get('update_id') + ) + repository_entity = RepositoryEntity.objects.get( + repository=repository_update.repository, + value=request.query_params.get('entity') + ) + + data = { + 'label': repository_entity.label, + 'label_value': repository_entity.label.value + } + return Response(data) + class RepositoryAuthorizationInfoViewSet( mixins.RetrieveModelMixin, @@ -240,6 +267,139 @@ def retrieve(self, request, *args, **kwargs): } return Response(data) + @action( + detail=True, + methods=['GET'], + url_name='evaluations', + lookup_field=[]) + def evaluations(self, request, **kwargs): + repository_update = RepositoryUpdate.objects.get( + id=request.query_params.get('update_id') + ) + evaluations = repository_update.repository.evaluations( + language=repository_update.language + ) + + data = [] + + for evaluate in evaluations: + entities = [] + + for evaluate_entity in evaluate.get_entities(repository_update.language): + entities.append( + { + 'start': evaluate_entity.start, + 'end': evaluate_entity.end, + 'value': evaluate.text[evaluate_entity.start:evaluate_entity.end], + 'entity': evaluate_entity.entity.value, + } + ) + + data.append( + { + 'text': evaluate.get_text(repository_update.language), + 'intent': evaluate.intent, + 'entities': entities + + } + ) + return Response(data) + + @action( + detail=True, + methods=['POST'], + url_name='evaluate_results', + lookup_field=[]) + def evaluateresults(self, request, **kwargs): + repository_update = RepositoryUpdate.objects.get( + id=request.data.get('update_id') + ) + + intents_score = RepositoryEvaluateResultScore.objects.create( + precision=request.data.get('intentprecision'), + f1_score=request.data.get('intentf1_score'), + accuracy=request.data.get('intentaccuracy'), + ) + + entities_score = RepositoryEvaluateResultScore.objects.create( + precision=request.data.get('entityprecision'), + f1_score=request.data.get('entityf1_score'), + accuracy=request.data.get('entityaccuracy'), + ) + + evaluate_result = RepositoryEvaluateResult.objects.create( + repository_update=repository_update, + entity_results=entities_score, + intent_results=intents_score, + matrix_chart=request.data.get('matrix_chart'), + confidence_chart=request.data.get('confidence_chart'), + log=json.dumps(request.data.get('log')), + ) + + return Response( + { + 'evaluate_id': evaluate_result.id, + 'evaluate_version': evaluate_result.version + } + ) + + @action( + detail=True, + methods=['POST'], + url_name='evaluate_results_intent', + lookup_field=[]) + def evaluateresultsintent(self, request, **kwargs): + evaluate_result = RepositoryEvaluateResult.objects.get( + id=request.data.get('evaluate_id') + ) + + intent_score = RepositoryEvaluateResultScore.objects.create( + precision=request.data.get('precision'), + recall=request.data.get('recall'), + f1_score=request.data.get('f1_score'), + support=request.data.get('support'), + ) + + RepositoryEvaluateResultIntent.objects.create( + intent=request.data.get('intent_key'), + evaluate_result=evaluate_result, + score=intent_score, + ) + + return Response({}) + + @action( + detail=True, + methods=['POST'], + url_name='evaluate_results_score', + lookup_field=[]) + def evaluateresultsscore(self, request, **kwargs): + evaluate_result = RepositoryEvaluateResult.objects.get( + id=request.data.get('evaluate_id') + ) + + repository_update = RepositoryUpdate.objects.get( + id=request.data.get('update_id') + ) + + entity_score = RepositoryEvaluateResultScore.objects.create( + precision=request.data.get('precision'), + recall=request.data.get('recall'), + f1_score=request.data.get('f1_score'), + support=request.data.get('support'), + ) + + RepositoryEvaluateResultEntity.objects.create( + entity=RepositoryEntity.objects.get( + repository=repository_update.repository, + value=request.data.get('entity_key'), + create_entity=False), + evaluate_result=evaluate_result, + score=entity_score, + ) + + return Response({}) + class NLPLangsViewSet( mixins.ListModelMixin, From 8153b310ccccc6cd5494b765fcf7d3ff6066e295 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Fri, 23 Aug 2019 16:05:13 -0300 Subject: [PATCH 135/207] [fix] PEP8 --- bothub/api/v2/nlp/views.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/bothub/api/v2/nlp/views.py b/bothub/api/v2/nlp/views.py index c067902a..4425c1b4 100644 --- a/bothub/api/v2/nlp/views.py +++ b/bothub/api/v2/nlp/views.py @@ -285,12 +285,17 @@ def evaluations(self, request, **kwargs): for evaluate in evaluations: entities = [] - for evaluate_entity in evaluate.get_entities(repository_update.language): + for evaluate_entity in evaluate.get_entities( + repository_update.language + ): entities.append( { 'start': evaluate_entity.start, 'end': evaluate_entity.end, - 'value': evaluate.text[evaluate_entity.start:evaluate_entity.end], + 'value': + evaluate.text[ + evaluate_entity.start:evaluate_entity.end + ], 'entity': evaluate_entity.entity.value, } ) From a5ea73aa96ce4e7dde0660b8db5d7c2527b1a51a Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Mon, 26 Aug 2019 15:16:55 -0300 Subject: [PATCH 136/207] Added check Auth Token --- bothub/api/v2/nlp/views.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/bothub/api/v2/nlp/views.py b/bothub/api/v2/nlp/views.py index 4425c1b4..a9963b90 100644 --- a/bothub/api/v2/nlp/views.py +++ b/bothub/api/v2/nlp/views.py @@ -2,7 +2,10 @@ import json from django.db import models +from django.utils.translation import gettext_lazy as _ + from rest_framework import mixins +from rest_framework import exceptions from rest_framework.decorators import action from rest_framework.response import Response from rest_framework.viewsets import GenericViewSet @@ -21,6 +24,16 @@ from bothub.common import languages +def check_auth(request): + try: + auth = request.META.get('HTTP_AUTHORIZATION').split() + auth = auth[1] + RepositoryAuthorization.objects.get(uuid=auth) + except Exception: + msg = _('Invalid token header.') + raise exceptions.AuthenticationFailed(msg) + + class RepositoryAuthorizationTrainViewSet( mixins.RetrieveModelMixin, mixins.CreateModelMixin, @@ -273,6 +286,7 @@ def retrieve(self, request, *args, **kwargs): url_name='evaluations', lookup_field=[]) def evaluations(self, request, **kwargs): + check_auth(request) repository_update = RepositoryUpdate.objects.get( id=request.query_params.get('update_id') ) @@ -413,6 +427,7 @@ class NLPLangsViewSet( permission_classes = [AllowAny] def list(self, request, *args, **kwargs): + check_auth(request) data = { 'english': [ languages.LANGUAGE_EN, @@ -442,6 +457,7 @@ class RepositoryUpdateInterpretersViewSet( permission_classes = [AllowAny] def retrieve(self, request, *args, **kwargs): + check_auth(request) update = self.get_object() data = { 'update_id': update.id, @@ -451,6 +467,7 @@ def retrieve(self, request, *args, **kwargs): return Response(data) def create(self, request, *args, **kwargs): + check_auth(request) repository = self.queryset.get(pk=request.data.get('id')) bot_data = base64.b64decode(request.data.get('bot_data')) repository.save_training(bot_data) From e3d5758b9165434c304d599b02441951daab457f Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Wed, 28 Aug 2019 14:15:14 -0300 Subject: [PATCH 137/207] Added Check Authorization Train and Evaluate --- bothub/api/v2/nlp/views.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/bothub/api/v2/nlp/views.py b/bothub/api/v2/nlp/views.py index a9963b90..e0ef54c2 100644 --- a/bothub/api/v2/nlp/views.py +++ b/bothub/api/v2/nlp/views.py @@ -65,6 +65,7 @@ def retrieve(self, request, *args, **kwargs): url_name='start_training', lookup_field=[]) def starttraining(self, request, **kwargs): + check_auth(request) repository = RepositoryUpdate.objects.get( id=request.data.get('update_id') ) @@ -117,6 +118,7 @@ def starttraining(self, request, **kwargs): url_name='gettext', lookup_field=[]) def gettext(self, request, **kwargs): + check_auth(request) repository = RepositoryUpdate.objects.get( id=request.query_params.get('update_id') ).examples.get( @@ -136,6 +138,7 @@ def gettext(self, request, **kwargs): url_name='get_entities', lookup_field=[]) def getentities(self, request, **kwargs): + check_auth(request) repository = RepositoryUpdate.objects.get( id=request.query_params.get('update_id') ).examples.get( @@ -160,6 +163,7 @@ def getentities(self, request, **kwargs): url_name='get_entities_label', lookup_field=[]) def getentitieslabel(self, request, **kwargs): + check_auth(request) repository = RepositoryUpdate.objects.get( id=request.query_params.get('update_id') ).examples.get( @@ -188,6 +192,7 @@ def getentitieslabel(self, request, **kwargs): url_name='train_fail', lookup_field=[]) def trainfail(self, request, **kwargs): + check_auth(request) RepositoryUpdate.objects.get( id=request.data.get('update_id') ).train_fail() @@ -199,6 +204,7 @@ def trainfail(self, request, **kwargs): url_name='training_log', lookup_field=[]) def traininglog(self, request, **kwargs): + check_auth(request) repository = RepositoryUpdate.objects.get( id=request.data.get('update_id') ) @@ -267,6 +273,7 @@ class RepositoryAuthorizationEvaluateViewSet( permission_classes = [AllowAny] def retrieve(self, request, *args, **kwargs): + check_auth(request) repository_authorization = self.get_object() repository = repository_authorization.repository update = repository.last_trained_update( @@ -330,6 +337,7 @@ def evaluations(self, request, **kwargs): url_name='evaluate_results', lookup_field=[]) def evaluateresults(self, request, **kwargs): + check_auth(request) repository_update = RepositoryUpdate.objects.get( id=request.data.get('update_id') ) @@ -368,6 +376,7 @@ def evaluateresults(self, request, **kwargs): url_name='evaluate_results_intent', lookup_field=[]) def evaluateresultsintent(self, request, **kwargs): + check_auth(request) evaluate_result = RepositoryEvaluateResult.objects.get( id=request.data.get('evaluate_id') ) @@ -393,6 +402,7 @@ def evaluateresultsintent(self, request, **kwargs): url_name='evaluate_results_score', lookup_field=[]) def evaluateresultsscore(self, request, **kwargs): + check_auth(request) evaluate_result = RepositoryEvaluateResult.objects.get( id=request.data.get('evaluate_id') ) @@ -427,7 +437,6 @@ class NLPLangsViewSet( permission_classes = [AllowAny] def list(self, request, *args, **kwargs): - check_auth(request) data = { 'english': [ languages.LANGUAGE_EN, From 55e8c4d4f3aa5c4e5c9f83d552f8cf0fbf017190 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Wed, 28 Aug 2019 14:55:16 -0300 Subject: [PATCH 138/207] Added check auth routers nlp --- bothub/api/v2/nlp/views.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/bothub/api/v2/nlp/views.py b/bothub/api/v2/nlp/views.py index e0ef54c2..c7ca6385 100644 --- a/bothub/api/v2/nlp/views.py +++ b/bothub/api/v2/nlp/views.py @@ -42,6 +42,7 @@ class RepositoryAuthorizationTrainViewSet( permission_classes = [AllowAny] def retrieve(self, request, *args, **kwargs): + check_auth(request) repository_authorization = self.get_object() current_update = repository_authorization.repository.current_update( str(request.query_params.get('language')) @@ -220,6 +221,7 @@ class RepositoryAuthorizationParseViewSet( permission_classes = [AllowAny] def retrieve(self, request, *args, **kwargs): + check_auth(request) repository_authorization = self.get_object() repository = repository_authorization.repository update = repository.last_trained_update( @@ -238,6 +240,7 @@ def retrieve(self, request, *args, **kwargs): url_name='repository_entity', lookup_field=[]) def repositoryentity(self, request, **kwargs): + check_auth(request) repository_update = RepositoryUpdate.objects.get( id=request.query_params.get('update_id') ) @@ -260,6 +263,7 @@ class RepositoryAuthorizationInfoViewSet( permission_classes = [AllowAny] def retrieve(self, request, *args, **kwargs): + check_auth(request) repository_authorization = self.get_object() repository = repository_authorization.repository serializer = RepositorySerializer(repository) From 81b576c000dd084f3afb82b2f0ced96fff24be46 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Thu, 29 Aug 2019 11:04:24 -0300 Subject: [PATCH 139/207] [fix] Views NLP serializers --- bothub/api/v2/nlp/serializers.py | 5 +++++ bothub/api/v2/nlp/views.py | 7 +++++++ 2 files changed, 12 insertions(+) create mode 100644 bothub/api/v2/nlp/serializers.py diff --git a/bothub/api/v2/nlp/serializers.py b/bothub/api/v2/nlp/serializers.py new file mode 100644 index 00000000..07f166df --- /dev/null +++ b/bothub/api/v2/nlp/serializers.py @@ -0,0 +1,5 @@ +from rest_framework import serializers + + +class NLPSerializer(serializers.Serializer): + pass diff --git a/bothub/api/v2/nlp/views.py b/bothub/api/v2/nlp/views.py index c7ca6385..1c273e22 100644 --- a/bothub/api/v2/nlp/views.py +++ b/bothub/api/v2/nlp/views.py @@ -12,6 +12,7 @@ from rest_framework.permissions import AllowAny from bothub.api.v2.repository.serializers import RepositorySerializer +from .serializers import NLPSerializer from bothub.authentication.models import User from bothub.common.models import RepositoryAuthorization from bothub.common.models import RepositoryEntity @@ -39,6 +40,7 @@ class RepositoryAuthorizationTrainViewSet( mixins.CreateModelMixin, GenericViewSet): queryset = RepositoryAuthorization.objects + serializer_class = NLPSerializer permission_classes = [AllowAny] def retrieve(self, request, *args, **kwargs): @@ -218,6 +220,7 @@ class RepositoryAuthorizationParseViewSet( mixins.RetrieveModelMixin, GenericViewSet): queryset = RepositoryAuthorization.objects + serializer_class = NLPSerializer permission_classes = [AllowAny] def retrieve(self, request, *args, **kwargs): @@ -260,6 +263,7 @@ class RepositoryAuthorizationInfoViewSet( mixins.RetrieveModelMixin, GenericViewSet): queryset = RepositoryAuthorization.objects + serializer_class = NLPSerializer permission_classes = [AllowAny] def retrieve(self, request, *args, **kwargs): @@ -274,6 +278,7 @@ class RepositoryAuthorizationEvaluateViewSet( mixins.RetrieveModelMixin, GenericViewSet): queryset = RepositoryAuthorization.objects + serializer_class = NLPSerializer permission_classes = [AllowAny] def retrieve(self, request, *args, **kwargs): @@ -438,6 +443,7 @@ class NLPLangsViewSet( mixins.ListModelMixin, GenericViewSet): queryset = RepositoryAuthorization.objects + serializer_class = NLPSerializer permission_classes = [AllowAny] def list(self, request, *args, **kwargs): @@ -467,6 +473,7 @@ class RepositoryUpdateInterpretersViewSet( mixins.CreateModelMixin, GenericViewSet): queryset = RepositoryUpdate.objects + serializer_class = NLPSerializer permission_classes = [AllowAny] def retrieve(self, request, *args, **kwargs): From d005e9eee3125e8795a94bf8643a79ef93c03cc3 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Thu, 29 Aug 2019 11:06:27 -0300 Subject: [PATCH 140/207] Added pragma no coveralls --- bothub/api/v2/nlp/views.py | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/bothub/api/v2/nlp/views.py b/bothub/api/v2/nlp/views.py index 1c273e22..1018350b 100644 --- a/bothub/api/v2/nlp/views.py +++ b/bothub/api/v2/nlp/views.py @@ -25,7 +25,7 @@ from bothub.common import languages -def check_auth(request): +def check_auth(request): # pragma: no cover try: auth = request.META.get('HTTP_AUTHORIZATION').split() auth = auth[1] @@ -43,7 +43,7 @@ class RepositoryAuthorizationTrainViewSet( serializer_class = NLPSerializer permission_classes = [AllowAny] - def retrieve(self, request, *args, **kwargs): + def retrieve(self, request, *args, **kwargs): # pragma: no cover check_auth(request) repository_authorization = self.get_object() current_update = repository_authorization.repository.current_update( @@ -67,7 +67,7 @@ def retrieve(self, request, *args, **kwargs): methods=['POST'], url_name='start_training', lookup_field=[]) - def starttraining(self, request, **kwargs): + def starttraining(self, request, **kwargs): # pragma: no cover check_auth(request) repository = RepositoryUpdate.objects.get( id=request.data.get('update_id') @@ -120,7 +120,7 @@ def starttraining(self, request, **kwargs): methods=['GET'], url_name='gettext', lookup_field=[]) - def gettext(self, request, **kwargs): + def gettext(self, request, **kwargs): # pragma: no cover check_auth(request) repository = RepositoryUpdate.objects.get( id=request.query_params.get('update_id') @@ -140,7 +140,7 @@ def gettext(self, request, **kwargs): methods=['GET'], url_name='get_entities', lookup_field=[]) - def getentities(self, request, **kwargs): + def getentities(self, request, **kwargs): # pragma: no cover check_auth(request) repository = RepositoryUpdate.objects.get( id=request.query_params.get('update_id') @@ -165,7 +165,7 @@ def getentities(self, request, **kwargs): methods=['GET'], url_name='get_entities_label', lookup_field=[]) - def getentitieslabel(self, request, **kwargs): + def getentitieslabel(self, request, **kwargs): # pragma: no cover check_auth(request) repository = RepositoryUpdate.objects.get( id=request.query_params.get('update_id') @@ -194,7 +194,7 @@ def getentitieslabel(self, request, **kwargs): methods=['POST'], url_name='train_fail', lookup_field=[]) - def trainfail(self, request, **kwargs): + def trainfail(self, request, **kwargs): # pragma: no cover check_auth(request) RepositoryUpdate.objects.get( id=request.data.get('update_id') @@ -206,7 +206,7 @@ def trainfail(self, request, **kwargs): methods=['POST'], url_name='training_log', lookup_field=[]) - def traininglog(self, request, **kwargs): + def traininglog(self, request, **kwargs): # pragma: no cover check_auth(request) repository = RepositoryUpdate.objects.get( id=request.data.get('update_id') @@ -223,7 +223,7 @@ class RepositoryAuthorizationParseViewSet( serializer_class = NLPSerializer permission_classes = [AllowAny] - def retrieve(self, request, *args, **kwargs): + def retrieve(self, request, *args, **kwargs): # pragma: no cover check_auth(request) repository_authorization = self.get_object() repository = repository_authorization.repository @@ -242,7 +242,7 @@ def retrieve(self, request, *args, **kwargs): methods=['GET'], url_name='repository_entity', lookup_field=[]) - def repositoryentity(self, request, **kwargs): + def repositoryentity(self, request, **kwargs): # pragma: no cover check_auth(request) repository_update = RepositoryUpdate.objects.get( id=request.query_params.get('update_id') @@ -266,7 +266,7 @@ class RepositoryAuthorizationInfoViewSet( serializer_class = NLPSerializer permission_classes = [AllowAny] - def retrieve(self, request, *args, **kwargs): + def retrieve(self, request, *args, **kwargs): # pragma: no cover check_auth(request) repository_authorization = self.get_object() repository = repository_authorization.repository @@ -281,7 +281,7 @@ class RepositoryAuthorizationEvaluateViewSet( serializer_class = NLPSerializer permission_classes = [AllowAny] - def retrieve(self, request, *args, **kwargs): + def retrieve(self, request, *args, **kwargs): # pragma: no cover check_auth(request) repository_authorization = self.get_object() repository = repository_authorization.repository @@ -301,7 +301,7 @@ def retrieve(self, request, *args, **kwargs): methods=['GET'], url_name='evaluations', lookup_field=[]) - def evaluations(self, request, **kwargs): + def evaluations(self, request, **kwargs): # pragma: no cover check_auth(request) repository_update = RepositoryUpdate.objects.get( id=request.query_params.get('update_id') @@ -345,7 +345,7 @@ def evaluations(self, request, **kwargs): methods=['POST'], url_name='evaluate_results', lookup_field=[]) - def evaluateresults(self, request, **kwargs): + def evaluateresults(self, request, **kwargs): # pragma: no cover check_auth(request) repository_update = RepositoryUpdate.objects.get( id=request.data.get('update_id') @@ -384,7 +384,7 @@ def evaluateresults(self, request, **kwargs): methods=['POST'], url_name='evaluate_results_intent', lookup_field=[]) - def evaluateresultsintent(self, request, **kwargs): + def evaluateresultsintent(self, request, **kwargs): # pragma: no cover check_auth(request) evaluate_result = RepositoryEvaluateResult.objects.get( id=request.data.get('evaluate_id') @@ -410,7 +410,7 @@ def evaluateresultsintent(self, request, **kwargs): methods=['POST'], url_name='evaluate_results_score', lookup_field=[]) - def evaluateresultsscore(self, request, **kwargs): + def evaluateresultsscore(self, request, **kwargs): # pragma: no cover check_auth(request) evaluate_result = RepositoryEvaluateResult.objects.get( id=request.data.get('evaluate_id') @@ -446,7 +446,7 @@ class NLPLangsViewSet( serializer_class = NLPSerializer permission_classes = [AllowAny] - def list(self, request, *args, **kwargs): + def list(self, request, *args, **kwargs): # pragma: no cover data = { 'english': [ languages.LANGUAGE_EN, @@ -476,7 +476,7 @@ class RepositoryUpdateInterpretersViewSet( serializer_class = NLPSerializer permission_classes = [AllowAny] - def retrieve(self, request, *args, **kwargs): + def retrieve(self, request, *args, **kwargs): # pragma: no cover check_auth(request) update = self.get_object() data = { @@ -486,7 +486,7 @@ def retrieve(self, request, *args, **kwargs): } return Response(data) - def create(self, request, *args, **kwargs): + def create(self, request, *args, **kwargs): # pragma: no cover check_auth(request) repository = self.queryset.get(pk=request.data.get('id')) bot_data = base64.b64decode(request.data.get('bot_data')) From cbe89f496816c00e9fd66013c9640805125159c7 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Thu, 29 Aug 2019 13:30:56 -0300 Subject: [PATCH 141/207] Updated router Repository path --- bothub/api/v2/routers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bothub/api/v2/routers.py b/bothub/api/v2/routers.py index 7fe51b45..ef552328 100644 --- a/bothub/api/v2/routers.py +++ b/bothub/api/v2/routers.py @@ -93,7 +93,7 @@ def get_lookup_regex(self, viewset, lookup_prefix=''): router = Router() -router.register('repository/repository', RepositoryViewSet) +router.register('repository', RepositoryViewSet) router.register('repository/repository-votes', RepositoryVotesViewSet) router.register('repository/repositories', RepositoriesViewSet) router.register( From cd74a483eb4de51bb9b58d32701e5d37d1e95060 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Thu, 29 Aug 2019 13:32:52 -0300 Subject: [PATCH 142/207] Update Router path test repository --- bothub/api/v2/tests/test_repository.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bothub/api/v2/tests/test_repository.py b/bothub/api/v2/tests/test_repository.py index b4453719..365c0a1f 100644 --- a/bothub/api/v2/tests/test_repository.py +++ b/bothub/api/v2/tests/test_repository.py @@ -1953,7 +1953,7 @@ def request(self, repository, token): 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), } request = self.factory.get( - '/v2/repository/repository/{}/'.format( + '/v2/repository/{}/'.format( str(repository.uuid)), **authorization_header) response = RepositoryViewSet.as_view( @@ -2003,7 +2003,7 @@ def test_languages_status(self): 'HTTP_AUTHORIZATION': 'Token {}'.format(self.user_token.key), } request = self.factory.get( - '/v2/repository/repository/{}/languagesstatus/'.format( + '/v2/repository/{}/languagesstatus/'.format( self.repository.uuid), **authorization_header) response = RepositoryViewSet.as_view( @@ -2087,7 +2087,7 @@ def request(self, repository, token): 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), } request = self.factory.get( - '/v2/repository/repository/{}/train/'.format( + '/v2/repository/{}/train/'.format( str(repository.uuid)), **authorization_header) response = RepositoryViewSet.as_view({'get': 'train'})(request) @@ -2126,7 +2126,7 @@ def request(self, repository, token, data): 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), } request = self.factory.post( - '/v2/repository/repository/{}/analyze/'.format( + '/v2/repository/{}/analyze/'.format( str(repository.uuid)), data, **authorization_header) From 91cf6a04b1091513519c6c3aa4ecd95361b5d28e Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Thu, 29 Aug 2019 16:48:08 -0300 Subject: [PATCH 143/207] Updated view nlp --- bothub/api/v2/nlp/views.py | 262 ++++++++++++++++++++----------------- 1 file changed, 142 insertions(+), 120 deletions(-) diff --git a/bothub/api/v2/nlp/views.py b/bothub/api/v2/nlp/views.py index 1018350b..98a3aecb 100644 --- a/bothub/api/v2/nlp/views.py +++ b/bothub/api/v2/nlp/views.py @@ -2,17 +2,18 @@ import json from django.db import models +from django.http import JsonResponse from django.utils.translation import gettext_lazy as _ +from django.shortcuts import get_object_or_404 from rest_framework import mixins from rest_framework import exceptions from rest_framework.decorators import action -from rest_framework.response import Response from rest_framework.viewsets import GenericViewSet from rest_framework.permissions import AllowAny from bothub.api.v2.repository.serializers import RepositorySerializer -from .serializers import NLPSerializer +from bothub.api.v2.nlp.serializers import NLPSerializer from bothub.authentication.models import User from bothub.common.models import RepositoryAuthorization from bothub.common.models import RepositoryEntity @@ -25,7 +26,7 @@ from bothub.common import languages -def check_auth(request): # pragma: no cover +def check_auth(request): try: auth = request.META.get('HTTP_AUTHORIZATION').split() auth = auth[1] @@ -43,14 +44,14 @@ class RepositoryAuthorizationTrainViewSet( serializer_class = NLPSerializer permission_classes = [AllowAny] - def retrieve(self, request, *args, **kwargs): # pragma: no cover + def retrieve(self, request, *args, **kwargs): check_auth(request) repository_authorization = self.get_object() current_update = repository_authorization.repository.current_update( str(request.query_params.get('language')) ) - data = { + return JsonResponse({ 'ready_for_train': current_update.ready_for_train, 'current_update_id': @@ -59,29 +60,30 @@ def retrieve(self, request, *args, **kwargs): # pragma: no cover repository_authorization.user.id, 'language': current_update.language - } - return Response(data) + }) @action( detail=True, methods=['POST'], url_name='start_training', lookup_field=[]) - def starttraining(self, request, **kwargs): # pragma: no cover + def starttraining(self, request, **kwargs): check_auth(request) - repository = RepositoryUpdate.objects.get( - id=request.data.get('update_id') + + repository = get_object_or_404( + RepositoryUpdate, + pk=request.data.get('update_id') ) - examples = [] - for example in repository.examples: - examples.append( - { - 'example_id': example.id, - 'example_intent': example.intent - } - ) + + examples = [ + { + 'example_id': example.id, + 'example_intent': example.intent + } for example in repository.examples + ] + repository.start_training( - User.objects.get(id=request.data.get('by_user')) + get_object_or_404(User, pk=request.data.get('by_user')) ) label_examples_query = [] @@ -98,7 +100,7 @@ def starttraining(self, request, **kwargs): # pragma: no cover } ) - data = { + return JsonResponse({ 'language': repository.language, 'update_id': repository.id, 'repository_uuid': str(repository.repository.uuid), @@ -112,108 +114,121 @@ def starttraining(self, request, **kwargs): # pragma: no cover Repository.ALGORITHM_STATISTICAL_MODEL, 'ALGORITHM_NEURAL_NETWORK_EXTERNAL': Repository.ALGORITHM_NEURAL_NETWORK_EXTERNAL - } - return Response(data) + }) @action( detail=True, methods=['GET'], url_name='gettext', lookup_field=[]) - def gettext(self, request, **kwargs): # pragma: no cover + def gettext(self, request, **kwargs): check_auth(request) - repository = RepositoryUpdate.objects.get( - id=request.query_params.get('update_id') - ).examples.get( - id=request.query_params.get('example_id') - ).get_text( - request.query_params.get('language') - ) - data = { + try: + update_id = int(request.query_params.get('update_id')) + example_id = int(request.query_params.get('example_id')) + except ValueError: + raise exceptions.NotFound() + + repository = get_object_or_404( + get_object_or_404( + RepositoryUpdate, + pk=update_id + ).examples, pk=example_id + ).get_text(request.query_params.get('language')) + + return JsonResponse({ 'get_text': repository - } - return Response(data) + }) @action( detail=True, methods=['GET'], url_name='get_entities', lookup_field=[]) - def getentities(self, request, **kwargs): # pragma: no cover + def getentities(self, request, **kwargs): check_auth(request) - repository = RepositoryUpdate.objects.get( - id=request.query_params.get('update_id') - ).examples.get( - id=request.query_params.get('example_id') - ).get_entities( - request.query_params.get('language') - ) - entities = [] + try: + update_id = int(request.query_params.get('update_id')) + example_id = int(request.query_params.get('example_id')) + except ValueError: + raise exceptions.NotFound() + + repository = get_object_or_404( + get_object_or_404( + RepositoryUpdate, + pk=update_id + ).examples, pk=example_id + ).get_entities(request.query_params.get('language')) - for entit in repository: - entities.append(entit.rasa_nlu_data) + entities = [entit.rasa_nlu_data for entit in repository] - data = { + return JsonResponse({ 'entities': entities, - } - return Response(data) + }) @action( detail=True, methods=['GET'], url_name='get_entities_label', lookup_field=[]) - def getentitieslabel(self, request, **kwargs): # pragma: no cover + def getentitieslabel(self, request, **kwargs): check_auth(request) - repository = RepositoryUpdate.objects.get( - id=request.query_params.get('update_id') - ).examples.get( - id=request.query_params.get('example_id') - ).get_entities( - request.query_params.get('language') - ) - entities = [] - - for example_entity in filter(lambda ee: ee.entity.label, repository): - entities.append( - example_entity.get_rasa_nlu_data( - label_as_entity=True - ) + try: + update_id = int(request.query_params.get('update_id')) + example_id = int(request.query_params.get('example_id')) + except ValueError: + raise exceptions.NotFound() + + repository = get_object_or_404( + get_object_or_404( + RepositoryUpdate, + pk=update_id + ).examples, pk=example_id + ).get_entities(request.query_params.get('language')) + + entities = [ + example_entity.get_rasa_nlu_data( + label_as_entity=True + ) for example_entity in filter( + lambda ee: ee.entity.label, repository ) + ] - data = { + return JsonResponse({ 'entities': entities, - } - return Response(data) + }) @action( detail=True, methods=['POST'], url_name='train_fail', lookup_field=[]) - def trainfail(self, request, **kwargs): # pragma: no cover + def trainfail(self, request, **kwargs): check_auth(request) - RepositoryUpdate.objects.get( - id=request.data.get('update_id') - ).train_fail() - return Response({}) + repository = get_object_or_404( + RepositoryUpdate, + pk=request.data.get('update_id') + ) + repository.train_fail() + return JsonResponse({}) @action( detail=True, methods=['POST'], url_name='training_log', lookup_field=[]) - def traininglog(self, request, **kwargs): # pragma: no cover + def traininglog(self, request, **kwargs): check_auth(request) - repository = RepositoryUpdate.objects.get( - id=request.data.get('update_id') + repository = get_object_or_404( + RepositoryUpdate, + pk=request.data.get('update_id') ) repository.training_log = request.data.get('training_log') repository.save(update_fields=['training_log']) - return Response({}) + return JsonResponse({}) class RepositoryAuthorizationParseViewSet( @@ -223,40 +238,40 @@ class RepositoryAuthorizationParseViewSet( serializer_class = NLPSerializer permission_classes = [AllowAny] - def retrieve(self, request, *args, **kwargs): # pragma: no cover + def retrieve(self, request, *args, **kwargs): check_auth(request) repository_authorization = self.get_object() repository = repository_authorization.repository update = repository.last_trained_update( str(request.query_params.get('language')) ) - data = { + return JsonResponse({ 'update': False if update is None else True, 'update_id': update.id, 'language': update.language - } - return Response(data) + }) @action( detail=True, methods=['GET'], url_name='repository_entity', lookup_field=[]) - def repositoryentity(self, request, **kwargs): # pragma: no cover + def repositoryentity(self, request, **kwargs): check_auth(request) - repository_update = RepositoryUpdate.objects.get( - id=request.query_params.get('update_id') + repository_update = get_object_or_404( + RepositoryUpdate, + pk=request.query_params.get('update_id') ) - repository_entity = RepositoryEntity.objects.get( + repository_entity = get_object_or_404( + RepositoryEntity, repository=repository_update.repository, value=request.query_params.get('entity') ) - data = { + return JsonResponse({ 'label': repository_entity.label, 'label_value': repository_entity.label.value - } - return Response(data) + }) class RepositoryAuthorizationInfoViewSet( @@ -266,12 +281,12 @@ class RepositoryAuthorizationInfoViewSet( serializer_class = NLPSerializer permission_classes = [AllowAny] - def retrieve(self, request, *args, **kwargs): # pragma: no cover + def retrieve(self, request, *args, **kwargs): check_auth(request) repository_authorization = self.get_object() repository = repository_authorization.repository serializer = RepositorySerializer(repository) - return Response(serializer.data) + return JsonResponse(serializer.data) class RepositoryAuthorizationEvaluateViewSet( @@ -281,30 +296,30 @@ class RepositoryAuthorizationEvaluateViewSet( serializer_class = NLPSerializer permission_classes = [AllowAny] - def retrieve(self, request, *args, **kwargs): # pragma: no cover + def retrieve(self, request, *args, **kwargs): check_auth(request) repository_authorization = self.get_object() repository = repository_authorization.repository update = repository.last_trained_update( str(request.query_params.get('language')) ) - data = { + return JsonResponse({ 'update': False if update is None else True, 'update_id': update.id, 'language': update.language, 'user_id': repository_authorization.user.id - } - return Response(data) + }) @action( detail=True, methods=['GET'], url_name='evaluations', lookup_field=[]) - def evaluations(self, request, **kwargs): # pragma: no cover + def evaluations(self, request, **kwargs): check_auth(request) - repository_update = RepositoryUpdate.objects.get( - id=request.query_params.get('update_id') + repository_update = get_object_or_404( + RepositoryUpdate, + pk=request.query_params.get('update_id') ) evaluations = repository_update.repository.evaluations( language=repository_update.language @@ -338,17 +353,18 @@ def evaluations(self, request, **kwargs): # pragma: no cover } ) - return Response(data) + return JsonResponse(data) @action( detail=True, methods=['POST'], url_name='evaluate_results', lookup_field=[]) - def evaluateresults(self, request, **kwargs): # pragma: no cover + def evaluateresults(self, request, **kwargs): check_auth(request) - repository_update = RepositoryUpdate.objects.get( - id=request.data.get('update_id') + repository_update = get_object_or_404( + RepositoryUpdate, + pk=request.data.get('update_id') ) intents_score = RepositoryEvaluateResultScore.objects.create( @@ -372,7 +388,7 @@ def evaluateresults(self, request, **kwargs): # pragma: no cover log=json.dumps(request.data.get('log')), ) - return Response( + return JsonResponse( { 'evaluate_id': evaluate_result.id, 'evaluate_version': evaluate_result.version @@ -384,10 +400,12 @@ def evaluateresults(self, request, **kwargs): # pragma: no cover methods=['POST'], url_name='evaluate_results_intent', lookup_field=[]) - def evaluateresultsintent(self, request, **kwargs): # pragma: no cover + def evaluateresultsintent(self, request, **kwargs): check_auth(request) - evaluate_result = RepositoryEvaluateResult.objects.get( - id=request.data.get('evaluate_id') + + evaluate_result = get_object_or_404( + RepositoryEvaluateResult, + pk=request.data.get('evaluate_id') ) intent_score = RepositoryEvaluateResultScore.objects.create( @@ -403,21 +421,24 @@ def evaluateresultsintent(self, request, **kwargs): # pragma: no cover score=intent_score, ) - return Response({}) + return JsonResponse({}) @action( detail=True, methods=['POST'], url_name='evaluate_results_score', lookup_field=[]) - def evaluateresultsscore(self, request, **kwargs): # pragma: no cover + def evaluateresultsscore(self, request, **kwargs): check_auth(request) - evaluate_result = RepositoryEvaluateResult.objects.get( - id=request.data.get('evaluate_id') + + evaluate_result = get_object_or_404( + RepositoryEvaluateResult, + pk=request.data.get('evaluate_id') ) - repository_update = RepositoryUpdate.objects.get( - id=request.data.get('update_id') + repository_update = get_object_or_404( + RepositoryUpdate, + pk=request.data.get('update_id') ) entity_score = RepositoryEvaluateResultScore.objects.create( @@ -436,7 +457,7 @@ def evaluateresultsscore(self, request, **kwargs): # pragma: no cover score=entity_score, ) - return Response({}) + return JsonResponse({}) class NLPLangsViewSet( @@ -446,8 +467,8 @@ class NLPLangsViewSet( serializer_class = NLPSerializer permission_classes = [AllowAny] - def list(self, request, *args, **kwargs): # pragma: no cover - data = { + def list(self, request, *args, **kwargs): + return JsonResponse({ 'english': [ languages.LANGUAGE_EN, ], @@ -464,8 +485,7 @@ def list(self, request, *args, **kwargs): # pragma: no cover 'br': [ languages.LANGUAGE_PT_BR, ], - } - return Response(data) + }) class RepositoryUpdateInterpretersViewSet( @@ -476,19 +496,21 @@ class RepositoryUpdateInterpretersViewSet( serializer_class = NLPSerializer permission_classes = [AllowAny] - def retrieve(self, request, *args, **kwargs): # pragma: no cover + def retrieve(self, request, *args, **kwargs): check_auth(request) update = self.get_object() - data = { + return JsonResponse({ 'update_id': update.id, 'repository_uuid': update.repository.uuid, 'bot_data': str(update.bot_data) - } - return Response(data) + }) - def create(self, request, *args, **kwargs): # pragma: no cover + def create(self, request, *args, **kwargs): check_auth(request) - repository = self.queryset.get(pk=request.data.get('id')) + repository = get_object_or_404( + RepositoryUpdate, + pk=request.data.get('id') + ) bot_data = base64.b64decode(request.data.get('bot_data')) repository.save_training(bot_data) - return Response({}) + return JsonResponse({}) From 1068d1934a2b252c78daf7a78ab4dd95f19dc4eb Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Thu, 29 Aug 2019 17:06:52 -0300 Subject: [PATCH 144/207] Updated routers path --- bothub/api/v2/nlp/views.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/bothub/api/v2/nlp/views.py b/bothub/api/v2/nlp/views.py index 98a3aecb..0886c934 100644 --- a/bothub/api/v2/nlp/views.py +++ b/bothub/api/v2/nlp/views.py @@ -67,7 +67,7 @@ def retrieve(self, request, *args, **kwargs): methods=['POST'], url_name='start_training', lookup_field=[]) - def starttraining(self, request, **kwargs): + def start_training(self, request, **kwargs): check_auth(request) repository = get_object_or_404( @@ -121,7 +121,7 @@ def starttraining(self, request, **kwargs): methods=['GET'], url_name='gettext', lookup_field=[]) - def gettext(self, request, **kwargs): + def get_text(self, request, **kwargs): check_auth(request) try: @@ -146,7 +146,7 @@ def gettext(self, request, **kwargs): methods=['GET'], url_name='get_entities', lookup_field=[]) - def getentities(self, request, **kwargs): + def get_entities(self, request, **kwargs): check_auth(request) try: @@ -173,7 +173,7 @@ def getentities(self, request, **kwargs): methods=['GET'], url_name='get_entities_label', lookup_field=[]) - def getentitieslabel(self, request, **kwargs): + def get_entities_label(self, request, **kwargs): check_auth(request) try: @@ -206,7 +206,7 @@ def getentitieslabel(self, request, **kwargs): methods=['POST'], url_name='train_fail', lookup_field=[]) - def trainfail(self, request, **kwargs): + def train_fail(self, request, **kwargs): check_auth(request) repository = get_object_or_404( RepositoryUpdate, @@ -220,7 +220,7 @@ def trainfail(self, request, **kwargs): methods=['POST'], url_name='training_log', lookup_field=[]) - def traininglog(self, request, **kwargs): + def training_log(self, request, **kwargs): check_auth(request) repository = get_object_or_404( RepositoryUpdate, @@ -256,7 +256,7 @@ def retrieve(self, request, *args, **kwargs): methods=['GET'], url_name='repository_entity', lookup_field=[]) - def repositoryentity(self, request, **kwargs): + def repository_entity(self, request, **kwargs): check_auth(request) repository_update = get_object_or_404( RepositoryUpdate, @@ -360,7 +360,7 @@ def evaluations(self, request, **kwargs): methods=['POST'], url_name='evaluate_results', lookup_field=[]) - def evaluateresults(self, request, **kwargs): + def evaluate_results(self, request, **kwargs): check_auth(request) repository_update = get_object_or_404( RepositoryUpdate, @@ -400,7 +400,7 @@ def evaluateresults(self, request, **kwargs): methods=['POST'], url_name='evaluate_results_intent', lookup_field=[]) - def evaluateresultsintent(self, request, **kwargs): + def evaluate_results_intent(self, request, **kwargs): check_auth(request) evaluate_result = get_object_or_404( @@ -428,7 +428,7 @@ def evaluateresultsintent(self, request, **kwargs): methods=['POST'], url_name='evaluate_results_score', lookup_field=[]) - def evaluateresultsscore(self, request, **kwargs): + def evaluate_results_score(self, request, **kwargs): check_auth(request) evaluate_result = get_object_or_404( From 810bc8870058187e472b6237475f147bb4527b07 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Thu, 29 Aug 2019 18:02:21 -0300 Subject: [PATCH 145/207] [fix] Response NLP --- bothub/api/v2/nlp/views.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bothub/api/v2/nlp/views.py b/bothub/api/v2/nlp/views.py index 0886c934..cefec7f2 100644 --- a/bothub/api/v2/nlp/views.py +++ b/bothub/api/v2/nlp/views.py @@ -9,6 +9,7 @@ from rest_framework import mixins from rest_framework import exceptions from rest_framework.decorators import action +from rest_framework.response import Response from rest_framework.viewsets import GenericViewSet from rest_framework.permissions import AllowAny @@ -286,7 +287,7 @@ def retrieve(self, request, *args, **kwargs): repository_authorization = self.get_object() repository = repository_authorization.repository serializer = RepositorySerializer(repository) - return JsonResponse(serializer.data) + return Response(serializer.data) class RepositoryAuthorizationEvaluateViewSet( From a89bca5dba5b76f214df96a699c64e51d66f91f5 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Fri, 30 Aug 2019 09:43:50 -0300 Subject: [PATCH 146/207] [fix] Response --- bothub/api/v2/nlp/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bothub/api/v2/nlp/views.py b/bothub/api/v2/nlp/views.py index cefec7f2..36faab97 100644 --- a/bothub/api/v2/nlp/views.py +++ b/bothub/api/v2/nlp/views.py @@ -354,7 +354,7 @@ def evaluations(self, request, **kwargs): } ) - return JsonResponse(data) + return Response(data) @action( detail=True, From d4b3bcd7e91619a20bf8c20ba711822e107cb690 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Fri, 30 Aug 2019 11:04:37 -0300 Subject: [PATCH 147/207] Added test nlp --- bothub/api/v2/nlp/views.py | 33 ++- bothub/api/v2/tests/test_nlp.py | 361 ++++++++++++++++++++++++++++++++ 2 files changed, 377 insertions(+), 17 deletions(-) create mode 100644 bothub/api/v2/tests/test_nlp.py diff --git a/bothub/api/v2/nlp/views.py b/bothub/api/v2/nlp/views.py index 36faab97..a3bd5f34 100644 --- a/bothub/api/v2/nlp/views.py +++ b/bothub/api/v2/nlp/views.py @@ -2,7 +2,6 @@ import json from django.db import models -from django.http import JsonResponse from django.utils.translation import gettext_lazy as _ from django.shortcuts import get_object_or_404 @@ -52,7 +51,7 @@ def retrieve(self, request, *args, **kwargs): str(request.query_params.get('language')) ) - return JsonResponse({ + return Response({ 'ready_for_train': current_update.ready_for_train, 'current_update_id': @@ -101,7 +100,7 @@ def start_training(self, request, **kwargs): } ) - return JsonResponse({ + return Response({ 'language': repository.language, 'update_id': repository.id, 'repository_uuid': str(repository.repository.uuid), @@ -138,7 +137,7 @@ def get_text(self, request, **kwargs): ).examples, pk=example_id ).get_text(request.query_params.get('language')) - return JsonResponse({ + return Response({ 'get_text': repository }) @@ -165,7 +164,7 @@ def get_entities(self, request, **kwargs): entities = [entit.rasa_nlu_data for entit in repository] - return JsonResponse({ + return Response({ 'entities': entities, }) @@ -198,7 +197,7 @@ def get_entities_label(self, request, **kwargs): ) ] - return JsonResponse({ + return Response({ 'entities': entities, }) @@ -214,7 +213,7 @@ def train_fail(self, request, **kwargs): pk=request.data.get('update_id') ) repository.train_fail() - return JsonResponse({}) + return Response({}) @action( detail=True, @@ -229,7 +228,7 @@ def training_log(self, request, **kwargs): ) repository.training_log = request.data.get('training_log') repository.save(update_fields=['training_log']) - return JsonResponse({}) + return Response({}) class RepositoryAuthorizationParseViewSet( @@ -246,7 +245,7 @@ def retrieve(self, request, *args, **kwargs): update = repository.last_trained_update( str(request.query_params.get('language')) ) - return JsonResponse({ + return Response({ 'update': False if update is None else True, 'update_id': update.id, 'language': update.language @@ -269,7 +268,7 @@ def repository_entity(self, request, **kwargs): value=request.query_params.get('entity') ) - return JsonResponse({ + return Response({ 'label': repository_entity.label, 'label_value': repository_entity.label.value }) @@ -304,7 +303,7 @@ def retrieve(self, request, *args, **kwargs): update = repository.last_trained_update( str(request.query_params.get('language')) ) - return JsonResponse({ + return Response({ 'update': False if update is None else True, 'update_id': update.id, 'language': update.language, @@ -389,7 +388,7 @@ def evaluate_results(self, request, **kwargs): log=json.dumps(request.data.get('log')), ) - return JsonResponse( + return Response( { 'evaluate_id': evaluate_result.id, 'evaluate_version': evaluate_result.version @@ -422,7 +421,7 @@ def evaluate_results_intent(self, request, **kwargs): score=intent_score, ) - return JsonResponse({}) + return Response({}) @action( detail=True, @@ -458,7 +457,7 @@ def evaluate_results_score(self, request, **kwargs): score=entity_score, ) - return JsonResponse({}) + return Response({}) class NLPLangsViewSet( @@ -469,7 +468,7 @@ class NLPLangsViewSet( permission_classes = [AllowAny] def list(self, request, *args, **kwargs): - return JsonResponse({ + return Response({ 'english': [ languages.LANGUAGE_EN, ], @@ -500,7 +499,7 @@ class RepositoryUpdateInterpretersViewSet( def retrieve(self, request, *args, **kwargs): check_auth(request) update = self.get_object() - return JsonResponse({ + return Response({ 'update_id': update.id, 'repository_uuid': update.repository.uuid, 'bot_data': str(update.bot_data) @@ -514,4 +513,4 @@ def create(self, request, *args, **kwargs): ) bot_data = base64.b64decode(request.data.get('bot_data')) repository.save_training(bot_data) - return JsonResponse({}) + return Response({}) diff --git a/bothub/api/v2/tests/test_nlp.py b/bothub/api/v2/tests/test_nlp.py new file mode 100644 index 00000000..e31ec272 --- /dev/null +++ b/bothub/api/v2/tests/test_nlp.py @@ -0,0 +1,361 @@ +import json + +from django.test import TestCase +from django.test import RequestFactory +from rest_framework import status + +from bothub.api.v2.nlp.views import RepositoryAuthorizationTrainViewSet +from bothub.api.v2.nlp.views import RepositoryAuthorizationInfoViewSet +from bothub.common import languages +from bothub.common.models import RepositoryAuthorization +from bothub.common.models import RepositoryExample +from bothub.common.models import RepositoryExampleEntity +from bothub.common.models import Repository +from bothub.common.models import RepositoryUpdate + +from .utils import create_user_and_token + + +class TrainStartTrainingTestCase(TestCase): + def setUp(self): + self.factory = RequestFactory() + + self.owner, self.owner_token = create_user_and_token('owner') + self.user, self.user_token = create_user_and_token() + + self.repository = Repository.objects.create( + owner=self.owner, + name='Testing', + slug='test', + language=languages.LANGUAGE_EN) + + self.repository_authorization = RepositoryAuthorization.objects.create( + user=self.user, + repository=self.repository, + role=3, + ) + + self.repository_update = RepositoryUpdate.objects.create( + repository=self.repository, + language=languages.LANGUAGE_EN, + algorithm='statistical_model', + ) + + def request(self, token): + authorization_header = { + 'HTTP_AUTHORIZATION': 'Bearer {}'.format(token), + } + request = self.factory.post( + '/v2/repository/nlp/authorization/train/start_training/', + json.dumps( + { + 'update_id': self.repository_update.pk, + 'by_user': self.user.pk + } + ), + content_type='application/json', + **authorization_header + ) + response = RepositoryAuthorizationTrainViewSet.as_view( + {'post': 'start_training'} + )(request) + response.render() + content_data = json.loads(response.content) + return (response, content_data,) + + def test_ok(self): + response, content_data = self.request( + str(self.repository_authorization.uuid) + ) + self.assertEqual( + response.status_code, + status.HTTP_200_OK) + + def test_not_auth(self): + response, content_data = self.request('NO-TOKEN') + self.assertEqual( + response.status_code, + status.HTTP_401_UNAUTHORIZED) + + +class TrainGetTextTestCase(TestCase): + def setUp(self): + self.factory = RequestFactory() + + self.owner, self.owner_token = create_user_and_token('owner') + self.user, self.user_token = create_user_and_token() + + self.repository = Repository.objects.create( + owner=self.owner, + name='Testing', + slug='test', + language=languages.LANGUAGE_EN) + + self.repository_authorization = RepositoryAuthorization.objects.create( + user=self.user, + repository=self.repository, + role=3, + ) + + self.repository_update = RepositoryUpdate.objects.create( + repository=self.repository, + language=languages.LANGUAGE_EN, + algorithm='statistical_model', + ) + + self.repository_examples = RepositoryExample.objects.create( + repository_update=self.repository_update, + text='hello', + intent='greet' + ) + + def request(self, token): + authorization_header = { + 'HTTP_AUTHORIZATION': 'Bearer {}'.format(token), + } + request = self.factory.get( + '/v2/repository/nlp/authorization/train/get_text/' + '?update_id={}&example_id={}&language={}'.format( + self.repository_update.pk, + self.repository_examples.pk, + languages.LANGUAGE_EN + ), + **authorization_header + ) + response = RepositoryAuthorizationTrainViewSet.as_view( + {'get': 'get_text'} + )(request) + response.render() + content_data = json.loads(response.content) + return (response, content_data,) + + def test_ok(self): + response, content_data = self.request( + str(self.repository_authorization.uuid) + ) + self.assertEqual( + content_data.get('get_text'), + 'hello' + ) + self.assertEqual( + response.status_code, + status.HTTP_200_OK) + + def test_not_auth(self): + response, content_data = self.request('NO-TOKEN') + self.assertEqual( + response.status_code, + status.HTTP_401_UNAUTHORIZED) + + +class TrainGetEntitiesTestCase(TestCase): + def setUp(self): + self.factory = RequestFactory() + + self.owner, self.owner_token = create_user_and_token('owner') + self.user, self.user_token = create_user_and_token() + + self.repository = Repository.objects.create( + owner=self.owner, + name='Testing', + slug='test', + language=languages.LANGUAGE_EN) + + self.repository_authorization = RepositoryAuthorization.objects.create( + user=self.user, + repository=self.repository, + role=3, + ) + + self.repository_update = RepositoryUpdate.objects.create( + repository=self.repository, + language=languages.LANGUAGE_EN, + algorithm='statistical_model', + ) + + self.repository_examples = RepositoryExample.objects.create( + repository_update=self.repository_update, + text='hello', + intent='greet' + ) + + RepositoryExampleEntity.objects.create( + repository_example=self.repository_examples, + start=11, + end=18, + entity='name' + ) + + def request(self, token): + authorization_header = { + 'HTTP_AUTHORIZATION': 'Bearer {}'.format(token), + } + request = self.factory.get( + '/v2/repository/nlp/authorization/train/get_entities/' + '?update_id={}&example_id={}&language={}'.format( + self.repository_update.pk, + self.repository_examples.pk, + languages.LANGUAGE_EN + ), + **authorization_header + ) + response = RepositoryAuthorizationTrainViewSet.as_view( + {'get': 'get_entities'} + )(request) + response.render() + content_data = json.loads(response.content) + return (response, content_data,) + + def test_ok(self): + response, content_data = self.request( + str(self.repository_authorization.uuid) + ) + self.assertEqual( + len(content_data.get('entities')), + 1 + ) + self.assertEqual( + response.status_code, + status.HTTP_200_OK) + + def test_not_auth(self): + response, content_data = self.request('NO-TOKEN') + self.assertEqual( + response.status_code, + status.HTTP_401_UNAUTHORIZED) + + +class TrainFailTestCase(TestCase): + def setUp(self): + self.factory = RequestFactory() + + self.owner, self.owner_token = create_user_and_token('owner') + self.user, self.user_token = create_user_and_token() + + self.repository = Repository.objects.create( + owner=self.owner, + name='Testing', + slug='test', + language=languages.LANGUAGE_EN) + + self.repository_authorization = RepositoryAuthorization.objects.create( + user=self.user, + repository=self.repository, + role=3, + ) + + self.repository_update = RepositoryUpdate.objects.create( + repository=self.repository, + language=languages.LANGUAGE_EN, + algorithm='statistical_model', + ) + + def request(self, token): + authorization_header = { + 'HTTP_AUTHORIZATION': 'Bearer {}'.format(token), + } + request = self.factory.post( + '/v2/repository/nlp/authorization/train/train_fail/', + json.dumps( + { + 'update_id': self.repository_update.pk + } + ), + content_type='application/json', + **authorization_header + ) + response = RepositoryAuthorizationTrainViewSet.as_view( + {'post': 'train_fail'} + )(request) + response.render() + content_data = json.loads(response.content) + return (response, content_data,) + + def test_ok(self): + response, content_data = self.request( + str(self.repository_authorization.uuid) + ) + self.assertIsNotNone( + RepositoryUpdate.objects.get( + pk=self.repository_update.pk + ).failed_at + ) + self.assertEqual( + response.status_code, + status.HTTP_200_OK) + + def test_not_auth(self): + response, content_data = self.request('NO-TOKEN') + self.assertEqual( + response.status_code, + status.HTTP_401_UNAUTHORIZED) + + +class AuthorizationInfoTestCase(TestCase): + def setUp(self): + self.factory = RequestFactory() + + self.owner, self.owner_token = create_user_and_token('owner') + self.user, self.user_token = create_user_and_token() + + self.repository = Repository.objects.create( + owner=self.owner, + name='Testing', + slug='test', + language=languages.LANGUAGE_EN) + + self.repository_authorization = RepositoryAuthorization.objects.create( + user=self.user, + repository=self.repository, + role=3, + ) + + self.repository_update = RepositoryUpdate.objects.create( + repository=self.repository, + language=languages.LANGUAGE_EN, + algorithm='statistical_model', + ) + + self.repository_examples = RepositoryExample.objects.create( + repository_update=self.repository_update, + text='hello', + intent='greet' + ) + + self.repository_entity = RepositoryExampleEntity.objects.create( + repository_example=self.repository_examples, + start=11, + end=18, + entity='name' + ) + + def request(self, token): + authorization_header = { + 'HTTP_AUTHORIZATION': 'Bearer {}'.format(token), + } + request = self.factory.get( + '/v2/repository/nlp/authorization/info/{}/'.format( + token + ), + **authorization_header + ) + response = RepositoryAuthorizationInfoViewSet.as_view( + {'get': 'retrieve'} + )(request, pk=token) + response.render() + content_data = json.loads(response.content) + return (response, content_data,) + + def test_ok(self): + response, content_data = self.request( + str(self.repository_authorization.uuid) + ) + self.assertEqual( + response.status_code, + status.HTTP_200_OK) + + def test_not_auth(self): + response, content_data = self.request('NO-TOKEN') + self.assertEqual( + response.status_code, + status.HTTP_401_UNAUTHORIZED) From 8e1ad31e41c9aa19a62b03150c6bde48744cee64 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Fri, 30 Aug 2019 14:59:17 -0300 Subject: [PATCH 148/207] Added column nlp_server for set url nlp custom --- bothub/api/v2/repository/serializers.py | 10 ++++++++++ .../migrations/0034_repository_nlp_server.py | 18 ++++++++++++++++++ bothub/common/models.py | 18 +++++++++++++++--- 3 files changed, 43 insertions(+), 3 deletions(-) create mode 100644 bothub/common/migrations/0034_repository_nlp_server.py diff --git a/bothub/api/v2/repository/serializers.py b/bothub/api/v2/repository/serializers.py index add751bf..7ec440cd 100644 --- a/bothub/api/v2/repository/serializers.py +++ b/bothub/api/v2/repository/serializers.py @@ -1,4 +1,5 @@ from django.utils.translation import gettext as _ +from django.conf import settings from rest_framework import serializers from rest_framework.exceptions import PermissionDenied @@ -188,6 +189,7 @@ class Meta: 'use_language_model_featurizer', 'use_competing_intents', 'use_name_entities', + 'nlp_server', ] read_only = [ 'uuid', @@ -199,6 +201,7 @@ class Meta: 'ready_for_train', 'created_at', 'authorization', + 'nlp_server', ] ref_name = None @@ -232,6 +235,13 @@ class Meta: request_authorization = serializers.SerializerMethodField() available_request_authorization = serializers.SerializerMethodField() entities = serializers.SerializerMethodField() + nlp_server = serializers.SerializerMethodField() + + def get_nlp_server(self, obj): + if obj.nlp_server: + return obj.nlp_server + else: + return settings.BOTHUB_NLP_BASE_URL def create(self, validated_data): validated_data.update({ diff --git a/bothub/common/migrations/0034_repository_nlp_server.py b/bothub/common/migrations/0034_repository_nlp_server.py new file mode 100644 index 00000000..bf417908 --- /dev/null +++ b/bothub/common/migrations/0034_repository_nlp_server.py @@ -0,0 +1,18 @@ +# Generated by Django 2.1.5 on 2019-08-30 17:57 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('common', '0033_auto_20190816_2030'), + ] + + operations = [ + migrations.AddField( + model_name='repository', + name='nlp_server', + field=models.URLField(blank=True, null=True, verbose_name='Base URL NLP'), + ), + ] diff --git a/bothub/common/models.py b/bothub/common/models.py index 176a5675..bb15aee9 100644 --- a/bothub/common/models.py +++ b/bothub/common/models.py @@ -183,11 +183,23 @@ class Meta: null=False ) + nlp_server = models.URLField( + _('Base URL NLP'), + null=True, + blank=True + ) + objects = RepositoryManager() - nlp_train_url = '{}train/'.format(settings.BOTHUB_NLP_BASE_URL) - nlp_analyze_url = '{}parse/'.format(settings.BOTHUB_NLP_BASE_URL) - nlp_evaluate_url = '{}evaluate/'.format(settings.BOTHUB_NLP_BASE_URL) + nlp_train_url = '{}train/'.format( + nlp_server if nlp_server else settings.BOTHUB_NLP_BASE_URL + ) + nlp_analyze_url = '{}parse/'.format( + nlp_server if nlp_server else settings.BOTHUB_NLP_BASE_URL + ) + nlp_evaluate_url = '{}evaluate/'.format( + nlp_server if nlp_server else settings.BOTHUB_NLP_BASE_URL + ) @classmethod def request_nlp_train(cls, user_authorization): From b6fe638298b8ab38dccdbcd353f181948477ef8b Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Fri, 30 Aug 2019 15:08:47 -0300 Subject: [PATCH 149/207] Updated if nlp server is not null --- bothub/api/v2/repository/serializers.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/bothub/api/v2/repository/serializers.py b/bothub/api/v2/repository/serializers.py index 7ec440cd..7d019182 100644 --- a/bothub/api/v2/repository/serializers.py +++ b/bothub/api/v2/repository/serializers.py @@ -240,8 +240,7 @@ class Meta: def get_nlp_server(self, obj): if obj.nlp_server: return obj.nlp_server - else: - return settings.BOTHUB_NLP_BASE_URL + return settings.BOTHUB_NLP_BASE_URL def create(self, validated_data): validated_data.update({ From 13eb97f0a08014f6cbfbab0f7062afebce2a63c0 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Fri, 30 Aug 2019 16:39:45 -0300 Subject: [PATCH 150/207] [fix] Conflicts routers repository --- bothub/api/v2/routers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bothub/api/v2/routers.py b/bothub/api/v2/routers.py index 08923d2c..5f45520b 100644 --- a/bothub/api/v2/routers.py +++ b/bothub/api/v2/routers.py @@ -99,7 +99,7 @@ def get_lookup_regex(self, viewset, lookup_prefix=''): router = Router() -router.register('repository', RepositoryViewSet) +router.register('repository/repository-info', RepositoryViewSet) router.register('repository/repository-votes', RepositoryVotesViewSet) router.register('repository/repositories', RepositoriesViewSet) router.register( From 74aac6277db1957a42d2baa8ee20d12399e019d7 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Fri, 30 Aug 2019 16:40:01 -0300 Subject: [PATCH 151/207] added router upload examples with json --- bothub/api/v2/repository/views.py | 48 +++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/bothub/api/v2/repository/views.py b/bothub/api/v2/repository/views.py index 84147c09..c55c15cc 100644 --- a/bothub/api/v2/repository/views.py +++ b/bothub/api/v2/repository/views.py @@ -1,3 +1,4 @@ +import json from django.utils.decorators import method_decorator from django_filters.rest_framework import DjangoFilterBackend from django.shortcuts import get_object_or_404 @@ -7,10 +8,12 @@ from drf_yasg.utils import swagger_auto_schema from rest_framework.decorators import action from rest_framework.exceptions import ValidationError +from rest_framework.exceptions import UnsupportedMediaType from rest_framework.exceptions import PermissionDenied from rest_framework.response import Response from rest_framework.viewsets import GenericViewSet from rest_framework import mixins +from rest_framework import parsers from rest_framework import status from rest_framework import permissions from rest_framework.permissions import IsAuthenticatedOrReadOnly @@ -475,6 +478,51 @@ def create(self, request, *args, **kwargs): self.permission_classes = [permissions.IsAuthenticated] return super().create(request, *args, **kwargs) + @action( + detail=True, + methods=['POST'], + url_name='repository-upload-examples', + parser_classes=[parsers.MultiPartParser]) + def upload_examples(self, request, **kwargs): + try: + repository = get_object_or_404( + Repository, + pk=request.data.get('repository') + ) + except DjangoValidationError: + raise PermissionDenied() + + user_authorization = repository.get_user_authorization(request.user) + if not user_authorization.can_write: + raise PermissionDenied() + + f = request.FILES.get('file') + try: + json_data = json.loads(f.read()) + except json.decoder.JSONDecodeError: + raise UnsupportedMediaType('json') + + count_added = 0 + not_added = [] + + for data in json_data: + response_data = data + response_data['repository'] = request.data.get('repository') + serializer = RepositoryExampleSerializer( + data=response_data, + context={'request': request} + ) + if serializer.is_valid(): + serializer.save() + count_added += 1 + else: + not_added.append(data) + + return Response({ + 'added': count_added, + 'not_added': not_added + }) + def perform_destroy(self, obj): if obj.deleted_in: raise APIException(_('Example already deleted')) From 7694797b5a3e7768835b69154a66c866db730bcc Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Fri, 30 Aug 2019 17:24:13 -0300 Subject: [PATCH 152/207] Added tests upload file examples --- bothub/api/v2/repository/views.py | 2 +- bothub/api/v2/tests/test_repository.py | 83 ++++++++++++++++++++++++++ 2 files changed, 84 insertions(+), 1 deletion(-) diff --git a/bothub/api/v2/repository/views.py b/bothub/api/v2/repository/views.py index c55c15cc..0e933709 100644 --- a/bothub/api/v2/repository/views.py +++ b/bothub/api/v2/repository/views.py @@ -498,7 +498,7 @@ def upload_examples(self, request, **kwargs): f = request.FILES.get('file') try: - json_data = json.loads(f.read()) + json_data = json.loads(f.read().decode()) except json.decoder.JSONDecodeError: raise UnsupportedMediaType('json') diff --git a/bothub/api/v2/tests/test_repository.py b/bothub/api/v2/tests/test_repository.py index 365c0a1f..d5abe902 100644 --- a/bothub/api/v2/tests/test_repository.py +++ b/bothub/api/v2/tests/test_repository.py @@ -1,6 +1,7 @@ import json import uuid +from django.core.files.uploadedfile import SimpleUploadedFile from django.test import TestCase from django.test import RequestFactory from django.test.client import MULTIPART_CONTENT @@ -1453,6 +1454,88 @@ def test_entity_has_valid_label(self): label) +class RepositoryExampleUploadTestCase(TestCase): + def setUp(self): + self.factory = RequestFactory() + + self.owner, self.owner_token = create_user_and_token('owner') + self.user, self.user_token = create_user_and_token() + + self.repository = Repository.objects.create( + owner=self.owner, + name='Testing', + slug='test', + language=languages.LANGUAGE_EN) + + def request(self, token): + authorization_header = { + 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), + } + examples = b'''[ + { + "text": "yes", + "language": "en", + "entities": [{ + "label": "yes", + "entity": "_yes", + "start": 0, + "end": 3 + }], + "intent": "greet" + }, + { + "text": "alright", + "language": "en", + "entities": [{ + "label": "yes", + "entity": "_yes", + "start": 0, + "end": 3 + }], + "intent": "greet" + } + ]''' + + uploaded_file = SimpleUploadedFile( + 'examples.json', + examples, + 'multipart/form-data' + ) + + request = self.factory.post( + '/v2/repository/example/upload_examples/', + { + 'file': uploaded_file, + 'repository': str(self.repository.uuid) + }, format='multipart', + **authorization_header) + response = RepositoryExampleViewSet.as_view( + {'post': 'upload_examples'})(request) + response.render() + content_data = json.loads(response.content) + return (response, content_data,) + + def test_okay(self): + response, content_data = self.request(self.owner_token) + self.assertEqual( + content_data.get('added'), + 2 + ) + self.assertEqual( + len(content_data.get('not_added')), + 0 + ) + self.assertEqual( + response.status_code, + status.HTTP_200_OK) + + def test_permission_denied(self): + response, content_data = self.request(self.user_token) + self.assertEqual( + response.status_code, + status.HTTP_403_FORBIDDEN) + + class RepositoryExampleDestroyTestCase(TestCase): def setUp(self): self.factory = RequestFactory() From 59b0b5a33320b85fdeedbd7ee920ca15c151d856 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Mon, 2 Sep 2019 08:23:00 -0300 Subject: [PATCH 153/207] [fix] Repository Upload swagger doc --- bothub/api/v2/repository/serializers.py | 4 ++++ bothub/api/v2/repository/views.py | 4 +++- bothub/api/v2/tests/test_repository.py | 18 +++++++++--------- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/bothub/api/v2/repository/serializers.py b/bothub/api/v2/repository/serializers.py index 7d019182..c3f39f30 100644 --- a/bothub/api/v2/repository/serializers.py +++ b/bothub/api/v2/repository/serializers.py @@ -595,3 +595,7 @@ class Meta: source='by', slug_field='nickname', read_only=True) + + +class RepositoryUpload(serializers.Serializer): + pass diff --git a/bothub/api/v2/repository/views.py b/bothub/api/v2/repository/views.py index 0e933709..0d1bb80a 100644 --- a/bothub/api/v2/repository/views.py +++ b/bothub/api/v2/repository/views.py @@ -44,6 +44,7 @@ from .serializers import AnalyzeTextSerializer from .serializers import EvaluateSerializer from .serializers import RepositoryUpdateSerializer +from .serializers import RepositoryUpload from .permissions import RepositoryPermission from .permissions import RepositoryAdminManagerAuthorization from .permissions import RepositoryExamplePermission @@ -482,7 +483,8 @@ def create(self, request, *args, **kwargs): detail=True, methods=['POST'], url_name='repository-upload-examples', - parser_classes=[parsers.MultiPartParser]) + parser_classes=[parsers.MultiPartParser], + serializer_class=RepositoryUpload) def upload_examples(self, request, **kwargs): try: repository = get_object_or_404( diff --git a/bothub/api/v2/tests/test_repository.py b/bothub/api/v2/tests/test_repository.py index d5abe902..c7b57601 100644 --- a/bothub/api/v2/tests/test_repository.py +++ b/bothub/api/v2/tests/test_repository.py @@ -127,7 +127,7 @@ def request(self, data, token=None): } if token else {} request = self.factory.post( - '/v2/repository/', + '/v2/repository/repository-info/', data, **authorization_header) @@ -191,7 +191,7 @@ def request(self, repository, token=None): } if token else {} request = self.factory.get( - '/v2/repository/{}/'.format(repository.uuid), + '/v2/repository/repository-info/{}/'.format(repository.uuid), **authorization_header) response = RepositoryViewSet.as_view({'get': 'retrieve'})( @@ -236,7 +236,7 @@ def request(self, repository, data={}, token=None): } if token else {} request = self.factory.patch( - '/v2/repository/{}/'.format(repository.uuid), + '/v2/repository/repository-info/{}/'.format(repository.uuid), self.factory._encode_data(data, MULTIPART_CONTENT), MULTIPART_CONTENT, **authorization_header) @@ -295,7 +295,7 @@ def request(self, repository, token=None): } if token else {} request = self.factory.get( - '/v2/repository/{}/'.format(repository.uuid), + '/v2/repository/repository-info/{}/'.format(repository.uuid), **authorization_header) response = RepositoryViewSet.as_view({'get': 'retrieve'})( @@ -344,7 +344,7 @@ def request(self, repository, token=None): } if token else {} request = self.factory.get( - '/v2/repository/{}/'.format(repository.uuid), + '/v2/repository/repository-info/{}/'.format(repository.uuid), **authorization_header) response = RepositoryViewSet.as_view({'get': 'retrieve'})( @@ -2036,7 +2036,7 @@ def request(self, repository, token): 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), } request = self.factory.get( - '/v2/repository/{}/'.format( + '/v2/repository/repository-info/{}/'.format( str(repository.uuid)), **authorization_header) response = RepositoryViewSet.as_view( @@ -2086,7 +2086,7 @@ def test_languages_status(self): 'HTTP_AUTHORIZATION': 'Token {}'.format(self.user_token.key), } request = self.factory.get( - '/v2/repository/{}/languagesstatus/'.format( + '/v2/repository/repository-info/{}/languagesstatus/'.format( self.repository.uuid), **authorization_header) response = RepositoryViewSet.as_view( @@ -2170,7 +2170,7 @@ def request(self, repository, token): 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), } request = self.factory.get( - '/v2/repository/{}/train/'.format( + '/v2/repository/repository-info/{}/train/'.format( str(repository.uuid)), **authorization_header) response = RepositoryViewSet.as_view({'get': 'train'})(request) @@ -2209,7 +2209,7 @@ def request(self, repository, token, data): 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), } request = self.factory.post( - '/v2/repository/{}/analyze/'.format( + '/v2/repository/repository-info/{}/analyze/'.format( str(repository.uuid)), data, **authorization_header) From 88d0a8a6a22c75c96ce6036aae155a01aa1c550f Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Mon, 2 Sep 2019 13:58:19 -0300 Subject: [PATCH 154/207] Refact bot_data, sending file to aws s3 --- Pipfile | 1 + Pipfile.lock | 60 ++++++++++++++++--- README.md | 4 ++ bothub/api/v2/nlp/views.py | 14 ++++- .../migrations/0035_auto_20190902_1455.py | 33 ++++++++++ bothub/common/models.py | 10 ++-- bothub/common/tests.py | 2 +- bothub/common/views.py | 8 +-- bothub/utils.py | 44 ++++++++++++++ docker-compose.yml | 4 ++ 10 files changed, 157 insertions(+), 23 deletions(-) create mode 100644 bothub/common/migrations/0035_auto_20190902_1455.py diff --git a/Pipfile b/Pipfile index 3c0f9de8..efb4aaf6 100644 --- a/Pipfile +++ b/Pipfile @@ -18,6 +18,7 @@ drf-yasg = "*" gunicorn = "*" gevent = "*" packaging = "*" +boto3 = "*" [dev-packages] "flake8" = "*" diff --git a/Pipfile.lock b/Pipfile.lock index c4ab89ec..612f26a1 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "5f230c8e911d5f0f91321351555b3277e4a6ce71b6fe1843271cefaf6f11559e" + "sha256": "ff59f9ce5bebac8c74b1789aacdad90b1a6e893773c29bf4e3cb840e29590cd5" }, "pipfile-spec": 6, "requires": { @@ -23,6 +23,21 @@ ], "version": "==19.1.0" }, + "boto3": { + "hashes": [ + "sha256:654c7ebd6d089d5af634a8121f3960e50e283643660abcba07e602ac237f4839", + "sha256:f114b586c307f73a46d6dfe9dfb1c37865354f48fc749794d96517527424d1f5" + ], + "index": "pypi", + "version": "==1.9.220" + }, + "botocore": { + "hashes": [ + "sha256:748fe4ee5cc8b10ef09e52c740b488402d6f6d4d1f0dde0c936da232b42b1bdd", + "sha256:9ffd9264e4ad999d2929cfe1c7e413d4cdf76a8bd92f011dce31874f056d2e18" + ], + "version": "==1.12.220" + }, "certifi": { "hashes": [ "sha256:046832c04d4e752f37383b628bc601a7ea7211496b4638f6514d0e5b9acc4939", @@ -92,6 +107,14 @@ "index": "pypi", "version": "==3.9.0" }, + "docutils": { + "hashes": [ + "sha256:6c4f696463b79f1fb8ba0c594b63840ebd41f059e92b31957c46b74a4599b6d0", + "sha256:9e4d7ecfc600058e07ba661411a2b7de2fd0fafa17d1a7f7361cd47b1175c827", + "sha256:a2aeea129088da402665e92e0b25b04b073c04b2dce4ab65caaa38b7ce2e1a99" + ], + "version": "==0.15.2" + }, "drf-yasg": { "hashes": [ "sha256:68fded2ffdf46e03f33e766184b7d8f1e1a5236f94acfd0c4ba932a57b812566", @@ -188,6 +211,13 @@ ], "version": "==2.10.1" }, + "jmespath": { + "hashes": [ + "sha256:3720a4b1bd659dd2eecad0666459b9788813e032b83e7ba58578e48254e0a0e6", + "sha256:bde2aef6f44302dfb30320115b17d030798de8c4110e28d5cf6cf91a7a31074c" + ], + "version": "==0.9.4" + }, "markupsafe": { "hashes": [ "sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473", @@ -236,6 +266,14 @@ ], "version": "==2.4.2" }, + "python-dateutil": { + "hashes": [ + "sha256:7e6584c74aeed623791615e26efd690f29817a27c73085b78e4bad02493df2fb", + "sha256:c89805f6f4d64db21ed966fda138f8a5ed7a4fdbc1a8ee329ce1b74e3c74da9e" + ], + "markers": "python_version >= '2.7'", + "version": "==2.8.0" + }, "python-decouple": { "hashes": [ "sha256:1317df14b43efee4337a4aa02914bf004f010cd56d6c4bd894e6474ec8c4fe2d" @@ -261,10 +299,10 @@ }, "ruamel.yaml": { "hashes": [ - "sha256:547aeab5c51c93bc750ed2a320c1559b605bde3aa569216aa75fd91d8a1c4623", - "sha256:c5e239b6a4f26baabb2e22b145582a7d99ae9d4ebb8902291365a61ed38faa7f" + "sha256:0db639b1b2742dae666c6fc009b8d1931ef15c9276ef31c0673cc6dcf766cf40", + "sha256:412a6f5cfdc0525dee6a27c08f5415c7fd832a7afcb7a0ed7319628aed23d408" ], - "version": "==0.16.1" + "version": "==0.16.5" }, "ruamel.yaml.clib": { "hashes": [ @@ -290,6 +328,13 @@ "markers": "platform_python_implementation == 'CPython' and python_version < '3.8'", "version": "==0.1.2" }, + "s3transfer": { + "hashes": [ + "sha256:6efc926738a3cd576c2a79725fed9afde92378aa5c6a957e3af010cb019fac9d", + "sha256:b780f2411b824cb541dbcd2c713d0cb61c7d1bcadae204cdddda2b35cef493ba" + ], + "version": "==0.2.1" + }, "six": { "hashes": [ "sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c", @@ -310,6 +355,7 @@ "sha256:2393a695cd12afedd0dcb26fe5d50d0cf248e5a66f75dbd89a3d4eb333a61af4", "sha256:a637e5fae88995b256e3409dc4d52c2e2e0ba32c42a6365fee8bbd2238de3cfb" ], + "markers": "python_version >= '3.4'", "version": "==1.24.3" }, "whitenoise": { @@ -406,11 +452,11 @@ }, "ipython": { "hashes": [ - "sha256:1d3a1692921e932751bc1a1f7bb96dc38671eeefdc66ed33ee4cbc57e92a410e", - "sha256:537cd0176ff6abd06ef3e23f2d0c4c2c8a4d9277b7451544c6cbf56d1c79a83d" + "sha256:c4ab005921641e40a68e405e286e7a1fcc464497e14d81b6914b4fd95e5dee9b", + "sha256:dd76831f065f17bddd7eaa5c781f5ea32de5ef217592cf019e34043b56895aa1" ], "index": "pypi", - "version": "==7.7.0" + "version": "==7.8.0" }, "ipython-genutils": { "hashes": [ diff --git a/README.md b/README.md index f79eb9d5..007728c1 100644 --- a/README.md +++ b/README.md @@ -76,3 +76,7 @@ You can set environment variables in your OS, write on ```.env``` file or pass v | BOTHUB_NLP_BASE_URL | ```string``` | ```http://localhost:2657/``` | The bothub-blp production application URL. Used to proxy requests. | CHECK_ACCESSIBLE_API_URL | ```string``` | ```http://localhost/api/repositories/``` | URL used by ```bothub.health.check.check_accessible_api``` to make a HTTP request. The response status code must be 200. | SEND_EMAILS | ```boolean``` | ```True``` | Send emails flag. +| BOTHUB_ENGINE_AWS_S3_BUCKET_NAME | ```string``` | ```None``` | +| BOTHUB_ENGINE_AWS_ACCESS_KEY_ID | ```string``` | ```None``` | +| BOTHUB_ENGINE_AWS_SECRET_ACCESS_KEY | ```string``` | ```None``` | +| BOTHUB_ENGINE_AWS_REGION_NAME | ```string``` | ```None``` | diff --git a/bothub/api/v2/nlp/views.py b/bothub/api/v2/nlp/views.py index a3bd5f34..b72a7344 100644 --- a/bothub/api/v2/nlp/views.py +++ b/bothub/api/v2/nlp/views.py @@ -1,5 +1,6 @@ import base64 import json +import requests from django.db import models from django.utils.translation import gettext_lazy as _ @@ -24,6 +25,7 @@ from bothub.common.models import RepositoryUpdate from bothub.common.models import Repository from bothub.common import languages +from bothub.utils import send_bot_data_file_aws def check_auth(request): @@ -499,18 +501,24 @@ class RepositoryUpdateInterpretersViewSet( def retrieve(self, request, *args, **kwargs): check_auth(request) update = self.get_object() + try: + download = requests.get(update.bot_data) + bot_data = base64.b64encode(download.content) + except Exception: + bot_data = b'' return Response({ 'update_id': update.id, 'repository_uuid': update.repository.uuid, - 'bot_data': str(update.bot_data) + 'bot_data': str(bot_data) }) def create(self, request, *args, **kwargs): check_auth(request) + id = request.data.get('id') repository = get_object_or_404( RepositoryUpdate, - pk=request.data.get('id') + pk=id ) bot_data = base64.b64decode(request.data.get('bot_data')) - repository.save_training(bot_data) + repository.save_training(send_bot_data_file_aws(id, bot_data)) return Response({}) diff --git a/bothub/common/migrations/0035_auto_20190902_1455.py b/bothub/common/migrations/0035_auto_20190902_1455.py new file mode 100644 index 00000000..f1cef359 --- /dev/null +++ b/bothub/common/migrations/0035_auto_20190902_1455.py @@ -0,0 +1,33 @@ +# Generated by Django 2.1.5 on 2019-09-02 14:55 + +from django.db import migrations, models +from bothub.utils import send_bot_data_file_aws +from bothub.common.models import RepositoryUpdate + + +def update_repository(apps, schema_editor): + for update in RepositoryUpdate.objects.all().exclude(bot_data__exact=''): + url = send_bot_data_file_aws(update.pk, update.bot_data) + repository_update = RepositoryUpdate.objects.get(pk=update.pk) + repository_update.bot_data = url + repository_update.save( + update_fields=[ + 'bot_data', + ]) + print('Updating bot_data repository_update {}'.format(str(update.pk))) + + +class Migration(migrations.Migration): + + dependencies = [ + ('common', '0034_repository_nlp_server'), + ] + + operations = [ + migrations.RunPython(update_repository), + migrations.AlterField( + model_name='repositoryupdate', + name='bot_data', + field=models.URLField(blank=True, verbose_name='bot data'), + ), + ] diff --git a/bothub/common/models.py b/bothub/common/models.py index bb15aee9..5335ce73 100644 --- a/bothub/common/models.py +++ b/bothub/common/models.py @@ -1,5 +1,4 @@ import uuid -import base64 import requests from functools import reduce @@ -489,10 +488,9 @@ class Meta: created_at = models.DateTimeField( _('created at'), auto_now_add=True) - bot_data = models.TextField( + bot_data = models.URLField( _('bot data'), - blank=True, - editable=False) + blank=True) by = models.ForeignKey( User, models.CASCADE, @@ -660,7 +658,7 @@ def save_training(self, bot_data): raise RepositoryUpdateAlreadyTrained() self.trained_at = timezone.now() - self.bot_data = base64.b64encode(bot_data).decode('utf8') + self.bot_data = bot_data self.repository.total_updates += 1 self.repository.save() self.save( @@ -670,7 +668,7 @@ def save_training(self, bot_data): ]) def get_bot_data(self): - return base64.b64decode(self.bot_data) + return self.bot_data def train_fail(self): self.failed_at = timezone.now() diff --git a/bothub/common/tests.py b/bothub/common/tests.py index 02d9e2a4..aebcb6b6 100644 --- a/bothub/common/tests.py +++ b/bothub/common/tests.py @@ -552,7 +552,7 @@ def test_train(self): update = self.repository.current_update() update.start_training(self.owner) - bot_data = b'bot_data__()\\\\//?(*)' + bot_data = 'https://s3.amazonaws.com' update.save_training(bot_data) self.assertEqual( diff --git a/bothub/common/views.py b/bothub/common/views.py index 7a9d7cf2..14b051ef 100644 --- a/bothub/common/views.py +++ b/bothub/common/views.py @@ -1,5 +1,5 @@ from django.shortcuts import get_object_or_404 -from django.http import HttpResponse +from django.http import HttpResponseRedirect from django.core.exceptions import ValidationError from django.contrib.admin.views.decorators import staff_member_required from .models import RepositoryUpdate @@ -10,9 +10,5 @@ def download_bot_data(self, update_id): # pragma: no cover update = get_object_or_404(RepositoryUpdate, id=update_id) if not update.trained_at: raise ValidationError('Update #{} not trained at.'.format(update.id)) - response = HttpResponse( - update.get_bot_data(), - content_type='application/gzip') - response['Content-Disposition'] = 'inline; filename={}.tar.gz'.format( - update.id) + response = HttpResponseRedirect(update.get_bot_data()) return response diff --git a/bothub/utils.py b/bothub/utils.py index 4c52b950..c4ecf2c4 100644 --- a/bothub/utils.py +++ b/bothub/utils.py @@ -1,3 +1,8 @@ +import io +import uuid +import boto3 +from decouple import config +from botocore.exceptions import ClientError from collections import OrderedDict @@ -10,3 +15,42 @@ def cast_supported_languages(i): def cast_empty_str_to_none(value): return value or None + + +def send_bot_data_file_aws(id, bot_data): + aws_access_key_id = config('BOTHUB_ENGINE_AWS_ACCESS_KEY_ID', default='') + aws_secret_access_key = config( + 'BOTHUB_ENGINE_AWS_SECRET_ACCESS_KEY', default='') + aws_bucket_name = config('BOTHUB_ENGINE_AWS_S3_BUCKET_NAME', default='') + aws_region_name = config('BOTHUB_ENGINE_AWS_REGION_NAME', 'us-east-1') + + confmat_url = '' + + if all([aws_access_key_id, aws_secret_access_key, aws_bucket_name]): + confmat_filename = 'repository_{}/bot_data_{}.tar.gz'.format( + str(id), uuid.uuid4()) + + botdata = io.BytesIO(bot_data) + + s3_client = boto3.client( + 's3', + aws_access_key_id=aws_access_key_id, + aws_secret_access_key=aws_secret_access_key, + region_name=aws_region_name, + ) + try: + s3_client.upload_fileobj( + botdata, + aws_bucket_name, + confmat_filename, + ExtraArgs={'ContentType': 'application/gzip'} + ) + confmat_url = '{}/{}/{}'.format( + s3_client.meta.endpoint_url, + aws_bucket_name, + confmat_filename + ) + except ClientError as e: + print(e) + + return confmat_url diff --git a/docker-compose.yml b/docker-compose.yml index 18561728..f67a3a0b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -50,6 +50,10 @@ services: - CHECK_ACCESSIBLE_API_URL=${CHECK_ACCESSIBLE_API_URL} - SEND_EMAILS=${SEND_EMAILS:-true} - SUPPORTED_LANGUAGES=${SUPPORTED_LANGUAGES:-en|pt} + - BOTHUB_ENGINE_AWS_ACCESS_KEY_ID=${BOTHUB_ENGINE_AWS_ACCESS_KEY_ID} + - BOTHUB_ENGINE_AWS_SECRET_ACCESS_KEY=${BOTHUB_ENGINE_AWS_SECRET_ACCESS_KEY} + - BOTHUB_ENGINE_AWS_S3_BUCKET_NAME=${BOTHUB_ENGINE_AWS_S3_BUCKET_NAME} + - BOTHUB_ENGINE_AWS_REGION_NAME=${BOTHUB_ENGINE_AWS_REGION_NAME} networks: From 10d7a84566cd07363d9660cf26de6e79e944d4ef Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Mon, 2 Sep 2019 14:01:49 -0300 Subject: [PATCH 155/207] Update column id to pk --- bothub/common/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bothub/common/views.py b/bothub/common/views.py index 14b051ef..e361d3c8 100644 --- a/bothub/common/views.py +++ b/bothub/common/views.py @@ -7,7 +7,7 @@ @staff_member_required def download_bot_data(self, update_id): # pragma: no cover - update = get_object_or_404(RepositoryUpdate, id=update_id) + update = get_object_or_404(RepositoryUpdate, pk=update_id) if not update.trained_at: raise ValidationError('Update #{} not trained at.'.format(update.id)) response = HttpResponseRedirect(update.get_bot_data()) From 70e7d89379ceb851285416eb4b8bec848627a463 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Fri, 13 Sep 2019 09:34:07 -0300 Subject: [PATCH 156/207] Updated PEP8 --- bothub/common/views.py | 2 +- bothub/utils.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bothub/common/views.py b/bothub/common/views.py index e361d3c8..53f77ff2 100644 --- a/bothub/common/views.py +++ b/bothub/common/views.py @@ -9,6 +9,6 @@ def download_bot_data(self, update_id): # pragma: no cover update = get_object_or_404(RepositoryUpdate, pk=update_id) if not update.trained_at: - raise ValidationError('Update #{} not trained at.'.format(update.id)) + raise ValidationError(f'Update #{update.pk} not trained at.') response = HttpResponseRedirect(update.get_bot_data()) return response diff --git a/bothub/utils.py b/bothub/utils.py index c4ecf2c4..e3b681cd 100644 --- a/bothub/utils.py +++ b/bothub/utils.py @@ -27,8 +27,8 @@ def send_bot_data_file_aws(id, bot_data): confmat_url = '' if all([aws_access_key_id, aws_secret_access_key, aws_bucket_name]): - confmat_filename = 'repository_{}/bot_data_{}.tar.gz'.format( - str(id), uuid.uuid4()) + confmat_filename = \ + f'repository_{str(id)}/bot_data_{uuid.uuid4()}.tar.gz' botdata = io.BytesIO(bot_data) From add0f6ca22a5c760cbdc016f1e9ac9fbb2a6b9cf Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Tue, 17 Sep 2019 11:37:34 -0300 Subject: [PATCH 157/207] [fix] Request NLP --- bothub/api/v1/views.py | 6 +++--- bothub/api/v2/repository/views.py | 6 +++--- bothub/common/models.py | 34 ++++++++++++++----------------- 3 files changed, 21 insertions(+), 25 deletions(-) diff --git a/bothub/api/v1/views.py b/bothub/api/v1/views.py index 8bb5a17e..04c38012 100644 --- a/bothub/api/v1/views.py +++ b/bothub/api/v1/views.py @@ -562,7 +562,7 @@ def train(self, request, **kwargs): user_authorization = repository.get_user_authorization(request.user) if not user_authorization.can_write: raise PermissionDenied() - request = Repository.request_nlp_train( # pragma: no cover + request = repository.request_nlp_train( # pragma: no cover user_authorization) if request.status_code != status.HTTP_200_OK: # pragma: no cover raise APIException( # pragma: no cover @@ -587,7 +587,7 @@ def analyze(self, request, **kwargs): serializer = AnalyzeTextSerializer( data=request.data) # pragma: no cover serializer.is_valid(raise_exception=True) # pragma: no cover - request = Repository.request_nlp_analyze( + request = repository.request_nlp_analyze( user_authorization, serializer.data) # pragma: no cover @@ -641,7 +641,7 @@ def evaluate(self, request, **kwargs): detail=_('You need to have at least ' + 'two registered intents')) # pragma: no cover - request = Repository.request_nlp_evaluate( # pragma: no cover + request = repository.request_nlp_evaluate( # pragma: no cover user_authorization, serializer.data) if request.status_code != status.HTTP_200_OK: # pragma: no cover raise APIException( # pragma: no cover diff --git a/bothub/api/v2/repository/views.py b/bothub/api/v2/repository/views.py index 0d1bb80a..4214cba7 100644 --- a/bothub/api/v2/repository/views.py +++ b/bothub/api/v2/repository/views.py @@ -106,7 +106,7 @@ def train(self, request, **kwargs): user_authorization = repository.get_user_authorization(request.user) if not user_authorization.can_write: raise PermissionDenied() - request = Repository.request_nlp_train( # pragma: no cover + request = repository.request_nlp_train( # pragma: no cover user_authorization) if request.status_code != status.HTTP_200_OK: # pragma: no cover raise APIException( # pragma: no cover @@ -126,7 +126,7 @@ def analyze(self, request, **kwargs): serializer = AnalyzeTextSerializer( data=request.data) # pragma: no cover serializer.is_valid(raise_exception=True) # pragma: no cover - request = Repository.request_nlp_analyze( + request = repository.request_nlp_analyze( user_authorization, serializer.data) # pragma: no cover @@ -176,7 +176,7 @@ def evaluate(self, request, **kwargs): detail=_('You need to have at least ' + 'two registered intents')) # pragma: no cover - request = Repository.request_nlp_evaluate( # pragma: no cover + request = repository.request_nlp_evaluate( # pragma: no cover user_authorization, serializer.data) if request.status_code != status.HTTP_200_OK: # pragma: no cover raise APIException( # pragma: no cover diff --git a/bothub/common/models.py b/bothub/common/models.py index bb15aee9..846a500b 100644 --- a/bothub/common/models.py +++ b/bothub/common/models.py @@ -191,21 +191,13 @@ class Meta: objects = RepositoryManager() - nlp_train_url = '{}train/'.format( - nlp_server if nlp_server else settings.BOTHUB_NLP_BASE_URL - ) - nlp_analyze_url = '{}parse/'.format( - nlp_server if nlp_server else settings.BOTHUB_NLP_BASE_URL - ) - nlp_evaluate_url = '{}evaluate/'.format( - nlp_server if nlp_server else settings.BOTHUB_NLP_BASE_URL - ) - - @classmethod - def request_nlp_train(cls, user_authorization): + def request_nlp_train(self, user_authorization): try: # pragma: no cover r = requests.post( # pragma: no cover - cls.nlp_train_url, + '{}train/'.format( + self.nlp_server if self.nlp_server else + settings.BOTHUB_NLP_BASE_URL + ), data={}, headers={'Authorization': 'Bearer {}'.format( user_authorization.uuid)}) @@ -215,11 +207,13 @@ def request_nlp_train(cls, user_authorization): {'status_code': status.HTTP_503_SERVICE_UNAVAILABLE}, code=status.HTTP_503_SERVICE_UNAVAILABLE) - @classmethod - def request_nlp_analyze(cls, user_authorization, data): + def request_nlp_analyze(self, user_authorization, data): try: # pragma: no cover r = requests.post( # pragma: no cover - cls.nlp_analyze_url, + '{}parse/'.format( + self.nlp_server if self.nlp_server else + settings.BOTHUB_NLP_BASE_URL + ), data={ 'text': data.get('text'), 'language': data.get('language'), @@ -232,11 +226,13 @@ def request_nlp_analyze(cls, user_authorization, data): {'status_code': status.HTTP_503_SERVICE_UNAVAILABLE}, code=status.HTTP_503_SERVICE_UNAVAILABLE) - @classmethod - def request_nlp_evaluate(cls, user_authorization, data): + def request_nlp_evaluate(self, user_authorization, data): try: # pragma: no cover r = requests.post( # pragma: no cover - cls.nlp_evaluate_url, + '{}evaluate/'.format( + self.nlp_server if self.nlp_server else + settings.BOTHUB_NLP_BASE_URL + ), data={ 'language': data.get('language'), }, From 3c9cfdb00933b31c64e691ebf43eb5a67d393520 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Wed, 18 Sep 2019 17:06:35 -0300 Subject: [PATCH 158/207] Update environment and added package environ --- Pipfile | 3 +- Pipfile.lock | 43 +++++++-------- bothub/health/checks.py | 6 +-- bothub/settings.py | 114 ++++++++++++++++++++-------------------- setup.py | 3 +- 5 files changed, 80 insertions(+), 89 deletions(-) diff --git a/Pipfile b/Pipfile index 3c0f9de8..7e02a3a4 100644 --- a/Pipfile +++ b/Pipfile @@ -5,8 +5,6 @@ name = "pypi" [packages] django = "==2.1.5" -dj-database-url = "==0.5.0" -python-decouple = "==3.1" djangorestframework = "==3.9.0" django-filter = "==2.0.0" django-cors-headers = "==2.4.0" @@ -18,6 +16,7 @@ drf-yasg = "*" gunicorn = "*" gevent = "*" packaging = "*" +django-environ = "*" [dev-packages] "flake8" = "*" diff --git a/Pipfile.lock b/Pipfile.lock index c4ab89ec..c0c8806c 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "5f230c8e911d5f0f91321351555b3277e4a6ce71b6fe1843271cefaf6f11559e" + "sha256": "410e323e9fac34de17c2c5f2db2d94b443a5c717ca7e73226ce764c88280eddb" }, "pipfile-spec": 6, "requires": { @@ -25,10 +25,10 @@ }, "certifi": { "hashes": [ - "sha256:046832c04d4e752f37383b628bc601a7ea7211496b4638f6514d0e5b9acc4939", - "sha256:945e3ba63a0b9f577b1395204e13c3a231f9bc0223888be653286534e5873695" + "sha256:e4f3620cfea4f83eedc95b24abd9cd56f3c4b146dd0177e83a21b4eb49e21e50", + "sha256:fd7c7c74727ddcf00e9acd26bba8da604ffec95bf1c2144e67aff7a8b50e6cef" ], - "version": "==2019.6.16" + "version": "==2019.9.11" }, "chardet": { "hashes": [ @@ -52,14 +52,6 @@ ], "version": "==0.0.4" }, - "dj-database-url": { - "hashes": [ - "sha256:4aeaeb1f573c74835b0686a2b46b85990571159ffc21aa57ecd4d1e1cb334163", - "sha256:851785365761ebe4994a921b433062309eb882fedd318e1b0fcecc607ed02da9" - ], - "index": "pypi", - "version": "==0.5.0" - }, "django": { "hashes": [ "sha256:a32c22af23634e1d11425574dce756098e015a165be02e4690179889b207c7a8", @@ -76,6 +68,14 @@ "index": "pypi", "version": "==2.4.0" }, + "django-environ": { + "hashes": [ + "sha256:6c9d87660142608f63ec7d5ce5564c49b603ea8ff25da595fd6098f6dc82afde", + "sha256:c57b3c11ec1f319d9474e3e5a79134f40174b17c7cc024bbb2fad84646b120c4" + ], + "index": "pypi", + "version": "==0.4.5" + }, "django-filter": { "hashes": [ "sha256:6f4e4bc1a11151178520567b50320e5c32f8edb552139d93ea3e30613b886f56", @@ -236,13 +236,6 @@ ], "version": "==2.4.2" }, - "python-decouple": { - "hashes": [ - "sha256:1317df14b43efee4337a4aa02914bf004f010cd56d6c4bd894e6474ec8c4fe2d" - ], - "index": "pypi", - "version": "==3.1" - }, "pytz": { "hashes": [ "sha256:31cb35c89bd7d333cd32c5f278fca91b523b0834369e757f4c5641ea252236ca", @@ -261,10 +254,10 @@ }, "ruamel.yaml": { "hashes": [ - "sha256:547aeab5c51c93bc750ed2a320c1559b605bde3aa569216aa75fd91d8a1c4623", - "sha256:c5e239b6a4f26baabb2e22b145582a7d99ae9d4ebb8902291365a61ed38faa7f" + "sha256:0db639b1b2742dae666c6fc009b8d1931ef15c9276ef31c0673cc6dcf766cf40", + "sha256:412a6f5cfdc0525dee6a27c08f5415c7fd832a7afcb7a0ed7319628aed23d408" ], - "version": "==0.16.1" + "version": "==0.16.5" }, "ruamel.yaml.clib": { "hashes": [ @@ -406,11 +399,11 @@ }, "ipython": { "hashes": [ - "sha256:1d3a1692921e932751bc1a1f7bb96dc38671eeefdc66ed33ee4cbc57e92a410e", - "sha256:537cd0176ff6abd06ef3e23f2d0c4c2c8a4d9277b7451544c6cbf56d1c79a83d" + "sha256:c4ab005921641e40a68e405e286e7a1fcc464497e14d81b6914b4fd95e5dee9b", + "sha256:dd76831f065f17bddd7eaa5c781f5ea32de5ef217592cf019e34043b56895aa1" ], "index": "pypi", - "version": "==7.7.0" + "version": "==7.8.0" }, "ipython-genutils": { "hashes": [ diff --git a/bothub/health/checks.py b/bothub/health/checks.py index 8e147b28..5eb753cd 100644 --- a/bothub/health/checks.py +++ b/bothub/health/checks.py @@ -1,14 +1,12 @@ import logging -from decouple import config +from ..settings import env from rest_framework import status logger = logging.getLogger('bothub.health.checks') -CHECK_ACCESSIBLE_API_URL = config( - 'CHECK_ACCESSIBLE_API_URL', - default=None) +CHECK_ACCESSIBLE_API_URL = env.str('CHECK_ACCESSIBLE_API_URL') def check_database_connection(**kwargs): diff --git a/bothub/settings.py b/bothub/settings.py index 9d006705..b663723f 100644 --- a/bothub/settings.py +++ b/bothub/settings.py @@ -1,27 +1,55 @@ import os -import dj_database_url -from decouple import config +import environ + from django.utils.log import DEFAULT_LOGGING from .utils import cast_supported_languages from .utils import cast_empty_str_to_none +environ.Env.read_env(env_file=(environ.Path(__file__) - 2)('.env')) + +env = environ.Env( + # set casting, default value + DEBUG=(bool, False), + ALLOWED_HOSTS=(lambda v: [s.strip() for s in v.split(',')], '*'), + LANGUAGE_CODE=(str, 'en-us'), + TIME_ZONE=(str, 'UTC'), + STATIC_URL=(str, '/static/'), + EMAIL_HOST=(cast_empty_str_to_none, None), + ADMINS=(lambda v: [ + ( + s.strip().split('|')[0], + s.strip().split('|')[1], + ) for s in v.split(',')] if v else [], []), + DEFAULT_FROM_EMAIL=(str, 'webmaster@localhost'), + SERVER_EMAIL=(str, 'root@localhost'), + EMAIL_PORT=(int, 25), + EMAIL_HOST_USER=(str, ''), + EMAIL_HOST_PASSWORD=(str, ''), + EMAIL_USE_SSL=(bool, False), + EMAIL_USE_TLS=(bool, False), + SEND_EMAILS=(bool, True), + BOTHUB_WEBAPP_BASE_URL=(str, 'http://localhost:8080/'), + BOTHUB_NLP_BASE_URL=(str, 'http://localhost:2657/'), + CSRF_COOKIE_DOMAIN=(cast_empty_str_to_none, None), + CSRF_COOKIE_SECURE=(bool, False), + SUPPORTED_LANGUAGES=(cast_supported_languages, 'en|pt'), + CHECK_ACCESSIBLE_API_URL=(str, None) +) + # Build paths inside the project like this: os.path.join(BASE_DIR, ...) BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = config('SECRET_KEY') +SECRET_KEY = env.str('SECRET_KEY') # SECURITY WARNING: don't run with debug turned on in production! -DEBUG = config('DEBUG', default=False, cast=bool) +DEBUG = env.bool('DEBUG') -ALLOWED_HOSTS = config( - 'ALLOWED_HOSTS', - default='*', - cast=lambda v: [s.strip() for s in v.split(',')]) +ALLOWED_HOSTS = env.list('ALLOWED_HOSTS') # Application definition @@ -78,11 +106,10 @@ # Database -DATABASES = {} -DATABASES['default'] = dj_database_url.parse( - config( - 'DEFAULT_DATABASE', - default='sqlite:///db.sqlite3')) + +DATABASES = { + 'default': env.db(var='DEFAULT_DATABASE', default='sqlite:///db.sqlite3') +} # Auth @@ -114,9 +141,9 @@ # Internationalization -LANGUAGE_CODE = config('LANGUAGE_CODE', default='en-us') +LANGUAGE_CODE = env.str('LANGUAGE_CODE') -TIME_ZONE = config('TIME_ZONE', default='UTC') +TIME_ZONE = env.str('TIME_ZONE') USE_I18N = True @@ -127,7 +154,7 @@ # Static files (CSS, JavaScript, Images) -STATIC_URL = config('STATIC_URL', default='/static/') +STATIC_URL = env.str('STATIC_URL') STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles') @@ -157,63 +184,41 @@ # mail -envvar_EMAIL_HOST = config( - 'EMAIL_HOST', - default=None, - cast=cast_empty_str_to_none) +envvar_EMAIL_HOST = env.str('EMAIL_HOST') -ADMINS = config( - 'ADMINS', - default='', - cast=lambda v: [ - ( - s.strip().split('|')[0], - s.strip().split('|')[1], - ) for s in v.split(',')] if v else []) +ADMINS = env.list('ADMINS') EMAIL_SUBJECT_PREFIX = '[bothub] ' -DEFAULT_FROM_EMAIL = config( - 'DEFAULT_FROM_EMAIL', - default='webmaster@localhost') -SERVER_EMAIL = config('SERVER_EMAIL', default='root@localhost') +DEFAULT_FROM_EMAIL = env.str('DEFAULT_FROM_EMAIL') +SERVER_EMAIL = env.str('SERVER_EMAIL') if envvar_EMAIL_HOST: EMAIL_HOST = envvar_EMAIL_HOST - EMAIL_PORT = config('EMAIL_PORT', default=25, cast=int) - EMAIL_HOST_USER = config('EMAIL_HOST_USER', default='') - EMAIL_HOST_PASSWORD = config('EMAIL_HOST_PASSWORD', default='') - EMAIL_USE_SSL = config('EMAIL_USE_SSL', default=False, cast=bool) - EMAIL_USE_TLS = config('EMAIL_USE_TLS', default=False, cast=bool) + EMAIL_PORT = env.int('EMAIL_PORT') + EMAIL_HOST_USER = env.str('EMAIL_HOST_USER') + EMAIL_HOST_PASSWORD = env.str('EMAIL_HOST_PASSWORD') + EMAIL_USE_SSL = env.bool('EMAIL_USE_SSL') + EMAIL_USE_TLS = env.bool('EMAIL_USE_TLS') else: EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' -SEND_EMAILS = config('SEND_EMAILS', default=True, cast=bool) +SEND_EMAILS = env.bool('SEND_EMAILS') # webapp -BOTHUB_WEBAPP_BASE_URL = config( - 'BOTHUB_WEBAPP_BASE_URL', - default='http://localhost:8080/') +BOTHUB_WEBAPP_BASE_URL = env.str('BOTHUB_WEBAPP_BASE_URL') # NLP -BOTHUB_NLP_BASE_URL = config( - 'BOTHUB_NLP_BASE_URL', - default='http://localhost:2657/') +BOTHUB_NLP_BASE_URL = env.str('BOTHUB_NLP_BASE_URL') # CSRF -CSRF_COOKIE_DOMAIN = config( - 'CSRF_COOKIE_DOMAIN', - default=None, - cast=cast_empty_str_to_none) +CSRF_COOKIE_DOMAIN = env.str('CSRF_COOKIE_DOMAIN') -CSRF_COOKIE_SECURE = config( - 'CSRF_COOKIE_SECURE', - default=False, - cast=bool) +CSRF_COOKIE_SECURE = env.bool('CSRF_COOKIE_SECURE') # Logging @@ -236,10 +241,7 @@ # Supported Languages -SUPPORTED_LANGUAGES = config( - 'SUPPORTED_LANGUAGES', - default='en|pt', - cast=cast_supported_languages) +SUPPORTED_LANGUAGES = env.str('SUPPORTED_LANGUAGES') # SECURE PROXY SSL HEADER diff --git a/setup.py b/setup.py index 75f37617..0420107a 100644 --- a/setup.py +++ b/setup.py @@ -8,8 +8,7 @@ packages=find_packages(), install_requires=[ 'django==2.1.3', - 'dj-database-url==0.5.0', - 'python-decouple==3.1', + 'django-environ==0.4.5', 'djangorestframework==3.9.0', 'django-filter==2.0.0', 'django-cors-headers==2.4.0', From 0b438e8310143d031cdc22735665bf6279f3e274 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Thu, 19 Sep 2019 08:45:19 -0300 Subject: [PATCH 159/207] [fix] Variable Environment --- bothub/settings.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/bothub/settings.py b/bothub/settings.py index b663723f..92556ab8 100644 --- a/bothub/settings.py +++ b/bothub/settings.py @@ -241,7 +241,12 @@ # Supported Languages -SUPPORTED_LANGUAGES = env.str('SUPPORTED_LANGUAGES') +SUPPORTED_LANGUAGES = env.get_value( + 'SUPPORTED_LANGUAGES', + cast_supported_languages, + 'en|pt', + True +) # SECURE PROXY SSL HEADER From 525cfe114eb25bebcba45e74f7c6cf013d8734be Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Thu, 19 Sep 2019 09:25:12 -0300 Subject: [PATCH 160/207] [fix] Variable Environment --- bothub/settings.py | 6 +++++- bothub/utils.py | 11 +++++------ 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/bothub/settings.py b/bothub/settings.py index 92556ab8..58df4822 100644 --- a/bothub/settings.py +++ b/bothub/settings.py @@ -36,7 +36,11 @@ CSRF_COOKIE_DOMAIN=(cast_empty_str_to_none, None), CSRF_COOKIE_SECURE=(bool, False), SUPPORTED_LANGUAGES=(cast_supported_languages, 'en|pt'), - CHECK_ACCESSIBLE_API_URL=(str, None) + CHECK_ACCESSIBLE_API_URL=(str, None), + BOTHUB_ENGINE_AWS_ACCESS_KEY_ID=(str, ''), + BOTHUB_ENGINE_AWS_SECRET_ACCESS_KEY=(str, ''), + BOTHUB_ENGINE_AWS_S3_BUCKET_NAME=(str, ''), + BOTHUB_ENGINE_AWS_REGION_NAME=(str, 'us-east-1') ) # Build paths inside the project like this: os.path.join(BASE_DIR, ...) diff --git a/bothub/utils.py b/bothub/utils.py index e3b681cd..0ab597fc 100644 --- a/bothub/utils.py +++ b/bothub/utils.py @@ -1,7 +1,7 @@ import io import uuid import boto3 -from decouple import config +from bothub.settings import env from botocore.exceptions import ClientError from collections import OrderedDict @@ -18,11 +18,10 @@ def cast_empty_str_to_none(value): def send_bot_data_file_aws(id, bot_data): - aws_access_key_id = config('BOTHUB_ENGINE_AWS_ACCESS_KEY_ID', default='') - aws_secret_access_key = config( - 'BOTHUB_ENGINE_AWS_SECRET_ACCESS_KEY', default='') - aws_bucket_name = config('BOTHUB_ENGINE_AWS_S3_BUCKET_NAME', default='') - aws_region_name = config('BOTHUB_ENGINE_AWS_REGION_NAME', 'us-east-1') + aws_access_key_id = env.str('BOTHUB_ENGINE_AWS_ACCESS_KEY_ID') + aws_secret_access_key = env.str('BOTHUB_ENGINE_AWS_SECRET_ACCESS_KEY') + aws_bucket_name = env.str('BOTHUB_ENGINE_AWS_S3_BUCKET_NAME') + aws_region_name = env.str('BOTHUB_ENGINE_AWS_REGION_NAME') confmat_url = '' From 77419e43ecca30ac594569bed4febcbf13818c4b Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Thu, 19 Sep 2019 09:28:26 -0300 Subject: [PATCH 161/207] [fix] Pipfile --- Pipfile.lock | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/Pipfile.lock b/Pipfile.lock index a2724b02..2cf3a28c 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "410e323e9fac34de17c2c5f2db2d94b443a5c717ca7e73226ce764c88280eddb" + "sha256": "763e79ede86d704b4ed149cd4146aa1539d334d3c949f5fc570b5c45bf431069" }, "pipfile-spec": 6, "requires": { @@ -16,27 +16,20 @@ ] }, "default": { - "attrs": { - "hashes": [ - "sha256:69c0dbf2ed392de1cb5ec704444b08a5ef81680a61cb899dc08127123af36a79", - "sha256:f0b870f674851ecbfbbbd364d6b5cbdff9dcedbc7f3f5e18a6891057f21fe399" - ], - "version": "==19.1.0" - }, "boto3": { "hashes": [ - "sha256:654c7ebd6d089d5af634a8121f3960e50e283643660abcba07e602ac237f4839", - "sha256:f114b586c307f73a46d6dfe9dfb1c37865354f48fc749794d96517527424d1f5" + "sha256:5d2665d1407c6dd932f609d72233b567a9959bf1409fc0e1b79ea6ff00f97324", + "sha256:b34199b188c03d233f23b39f1149d78e0edda6f69da09de9c46ba67f2850cec6" ], "index": "pypi", - "version": "==1.9.220" + "version": "==1.9.231" }, "botocore": { "hashes": [ - "sha256:748fe4ee5cc8b10ef09e52c740b488402d6f6d4d1f0dde0c936da232b42b1bdd", - "sha256:9ffd9264e4ad999d2929cfe1c7e413d4cdf76a8bd92f011dce31874f056d2e18" + "sha256:535d8a81418d7cac9de83abac1733c4e79dc5d0645c884c0d680c72df2d7825a", + "sha256:b9d0248ca2dae2b15a29f2d29d81175072a3ffb48056238d6d9584597810878d" ], - "version": "==1.12.220" + "version": "==1.12.231" }, "certifi": { "hashes": [ @@ -253,11 +246,11 @@ }, "packaging": { "hashes": [ - "sha256:a7ac867b97fdc07ee80a8058fe4435ccd274ecc3b0ed61d852d7d53055528cf9", - "sha256:c491ca87294da7cc01902edbe30a5bc6c4c28172b5138ab4e4aa1b9d7bfaeafe" + "sha256:28b924174df7a2fa32c1953825ff29c61e2f5e082343165438812f00d3a7fc47", + "sha256:d9551545c6d761f3def1677baf08ab2a3ca17c56879e70fecba2fc4dde4ed108" ], "index": "pypi", - "version": "==19.1" + "version": "==19.2" }, "pyparsing": { "hashes": [ @@ -266,6 +259,14 @@ ], "version": "==2.4.2" }, + "python-dateutil": { + "hashes": [ + "sha256:7e6584c74aeed623791615e26efd690f29817a27c73085b78e4bad02493df2fb", + "sha256:c89805f6f4d64db21ed966fda138f8a5ed7a4fdbc1a8ee329ce1b74e3c74da9e" + ], + "markers": "python_version >= '2.7'", + "version": "==2.8.0" + }, "pytz": { "hashes": [ "sha256:31cb35c89bd7d333cd32c5f278fca91b523b0834369e757f4c5641ea252236ca", From dc56ed75221df57b5c63e3f23885aebd0937b154 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Thu, 19 Sep 2019 09:32:34 -0300 Subject: [PATCH 162/207] [fix] Variable Environment --- bothub/settings.py | 8 ++++++++ bothub/utils.py | 20 ++++++++------------ 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/bothub/settings.py b/bothub/settings.py index 58df4822..0f908f4b 100644 --- a/bothub/settings.py +++ b/bothub/settings.py @@ -272,3 +272,11 @@ }, }, } + + +# AWS + +AWS_ACCESS_KEY_ID = env.str('BOTHUB_ENGINE_AWS_ACCESS_KEY_ID') +AWS_SECRET_ACCESS_KEY = env.str('BOTHUB_ENGINE_AWS_SECRET_ACCESS_KEY') +AWS_BUCKET_NAME = env.str('BOTHUB_ENGINE_AWS_S3_BUCKET_NAME') +AWS_REGION_NAME = env.str('BOTHUB_ENGINE_AWS_REGION_NAME') diff --git a/bothub/utils.py b/bothub/utils.py index 0ab597fc..4f0e2259 100644 --- a/bothub/utils.py +++ b/bothub/utils.py @@ -1,7 +1,7 @@ import io import uuid import boto3 -from bothub.settings import env +from django.conf import settings from botocore.exceptions import ClientError from collections import OrderedDict @@ -18,14 +18,10 @@ def cast_empty_str_to_none(value): def send_bot_data_file_aws(id, bot_data): - aws_access_key_id = env.str('BOTHUB_ENGINE_AWS_ACCESS_KEY_ID') - aws_secret_access_key = env.str('BOTHUB_ENGINE_AWS_SECRET_ACCESS_KEY') - aws_bucket_name = env.str('BOTHUB_ENGINE_AWS_S3_BUCKET_NAME') - aws_region_name = env.str('BOTHUB_ENGINE_AWS_REGION_NAME') - confmat_url = '' - if all([aws_access_key_id, aws_secret_access_key, aws_bucket_name]): + if all([settings.AWS_ACCESS_KEY_ID, settings.AWS_SECRET_ACCESS_KEY, + settings.AWS_BUCKET_NAME]): confmat_filename = \ f'repository_{str(id)}/bot_data_{uuid.uuid4()}.tar.gz' @@ -33,20 +29,20 @@ def send_bot_data_file_aws(id, bot_data): s3_client = boto3.client( 's3', - aws_access_key_id=aws_access_key_id, - aws_secret_access_key=aws_secret_access_key, - region_name=aws_region_name, + aws_access_key_id=settings.AWS_ACCESS_KEY_ID, + aws_secret_access_key=settings.AWS_SECRET_ACCESS_KEY, + region_name=settings.AWS_REGION_NAME, ) try: s3_client.upload_fileobj( botdata, - aws_bucket_name, + settings.AWS_BUCKET_NAME, confmat_filename, ExtraArgs={'ContentType': 'application/gzip'} ) confmat_url = '{}/{}/{}'.format( s3_client.meta.endpoint_url, - aws_bucket_name, + settings.AWS_BUCKET_NAME, confmat_filename ) except ClientError as e: From 6fbc1c89a69a0c609261ea064d029a10869dab22 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Fri, 20 Sep 2019 13:26:33 -0300 Subject: [PATCH 163/207] [fix] dependencies vulnerabilities --- Pipfile | 4 ++-- Pipfile.lock | 26 +++++++++++++------------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/Pipfile b/Pipfile index 5dd58763..611dd795 100644 --- a/Pipfile +++ b/Pipfile @@ -4,8 +4,8 @@ verify_ssl = true name = "pypi" [packages] -django = "==2.1.5" -djangorestframework = "==3.9.0" +django = "==2.1.11" +djangorestframework = "==3.9.1" django-filter = "==2.0.0" django-cors-headers = "==2.4.0" requests = "==2.20.1" diff --git a/Pipfile.lock b/Pipfile.lock index 2cf3a28c..f4a62335 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "763e79ede86d704b4ed149cd4146aa1539d334d3c949f5fc570b5c45bf431069" + "sha256": "1fbd5293399ec55bf270b7e84723abb49d41b54bd77625cbb37e1062db428ef5" }, "pipfile-spec": 6, "requires": { @@ -18,18 +18,18 @@ "default": { "boto3": { "hashes": [ - "sha256:5d2665d1407c6dd932f609d72233b567a9959bf1409fc0e1b79ea6ff00f97324", - "sha256:b34199b188c03d233f23b39f1149d78e0edda6f69da09de9c46ba67f2850cec6" + "sha256:0e4d047feb4d7d701e9b2107f10bb8d674952243385cd35d0b413a273c299751", + "sha256:67f957389cf56fb4c24c1093c6d58baebe6cf18139f6dca0f8a177239b0a4f8c" ], "index": "pypi", - "version": "==1.9.231" + "version": "==1.9.232" }, "botocore": { "hashes": [ - "sha256:535d8a81418d7cac9de83abac1733c4e79dc5d0645c884c0d680c72df2d7825a", - "sha256:b9d0248ca2dae2b15a29f2d29d81175072a3ffb48056238d6d9584597810878d" + "sha256:724d2349198c6f15f3cee0c0e4d33ecf4435e6d0db311bb79a3a28f6cf5a4090", + "sha256:a57a8fd0145c68e31bb4baab549b27a12f6695068c8dd5f2901d8dc06572dbeb" ], - "version": "==1.12.231" + "version": "==1.12.232" }, "certifi": { "hashes": [ @@ -62,11 +62,11 @@ }, "django": { "hashes": [ - "sha256:a32c22af23634e1d11425574dce756098e015a165be02e4690179889b207c7a8", - "sha256:d6393918da830530a9516bbbcbf7f1214c3d733738779f06b0f649f49cc698c3" + "sha256:1a41831eace203fd1939edf899e07d7abd12ce9bafc3d9a5a63a24a8d1d12bd5", + "sha256:305b6c4fce9e03bb746e35780c2c4d52f29ea1669f15633cfd41bc8821c74c76" ], "index": "pypi", - "version": "==2.1.5" + "version": "==2.1.11" }, "django-cors-headers": { "hashes": [ @@ -94,11 +94,11 @@ }, "djangorestframework": { "hashes": [ - "sha256:607865b0bb1598b153793892101d881466bd5a991de12bd6229abb18b1c86136", - "sha256:63f76cbe1e7d12b94c357d7e54401103b2e52aef0f7c1650d6c820ad708776e5" + "sha256:79c6efbb2514bc50cf25906d7c0a5cfead714c7af667ff4bd110312cd380ae66", + "sha256:a4138613b67e3a223be6c97f53b13d759c5b90d2b433bad670b8ebf95402075f" ], "index": "pypi", - "version": "==3.9.0" + "version": "==3.9.1" }, "docutils": { "hashes": [ From 8a21c60db55cbc431967e8b8a9763ca71e8f03b6 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Fri, 20 Sep 2019 13:28:53 -0300 Subject: [PATCH 164/207] [fix] dependencies vulnerabilities --- setup.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index 0420107a..e1192022 100644 --- a/setup.py +++ b/setup.py @@ -7,9 +7,9 @@ description='Bothub Engine', packages=find_packages(), install_requires=[ - 'django==2.1.3', + 'django==2.1.11', 'django-environ==0.4.5', - 'djangorestframework==3.9.0', + 'djangorestframework==3.9.1', 'django-filter==2.0.0', 'django-cors-headers==2.4.0', 'requests==2.20.1', From 2f3b3057e948f3961a70d9fbd81c5673ba2e117a Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Mon, 23 Sep 2019 10:18:19 -0300 Subject: [PATCH 165/207] Updated README --- README.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 007728c1..b95f8534 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,14 @@ +

+ Bothub +

+ # Bothub -[![Build Status](https://travis-ci.org/Ilhasoft/bothub-engine.svg?branch=master)](https://travis-ci.org/Ilhasoft/bothub-engine) [![Coverage Status](https://coveralls.io/repos/github/Ilhasoft/bothub-engine/badge.svg?branch=master)](https://coveralls.io/github/Ilhasoft/bothub-engine?branch=master) [![Python Version](https://img.shields.io/badge/python-3.6-blue.svg)](https://www.python.org/) [![License GPL-3.0](https://img.shields.io/badge/license-%20GPL--3.0-yellow.svg)](https://github.com/Ilhasoft/bothub-engine/blob/master/LICENSE) +[![Build Status](https://travis-ci.org/Ilhasoft/bothub-engine.svg?branch=master)](https://travis-ci.org/Ilhasoft/bothub-engine) +[![Coverage Status](https://coveralls.io/repos/github/Ilhasoft/bothub-engine/badge.svg?branch=master)](https://coveralls.io/github/Ilhasoft/bothub-engine?branch=master) +[![Code Climate](https://codeclimate.com/github/Ilhasoft/bothub-engine/badges/gpa.svg)](https://codeclimate.com/github/Ilhasoft/bothub-engine) +[![Python Version](https://img.shields.io/badge/python-3.6-blue.svg)](https://www.python.org/) +[![License GPL-3.0](https://img.shields.io/badge/license-%20GPL--3.0-yellow.svg)](https://github.com/Ilhasoft/bothub-engine/blob/master/LICENSE) ## Development From d68e5085a8c9482ed25af90ea7dd5570286b951d Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Mon, 23 Sep 2019 10:27:11 -0300 Subject: [PATCH 166/207] Updated README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b95f8534..9d6f9b96 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ # Bothub [![Build Status](https://travis-ci.org/Ilhasoft/bothub-engine.svg?branch=master)](https://travis-ci.org/Ilhasoft/bothub-engine) -[![Coverage Status](https://coveralls.io/repos/github/Ilhasoft/bothub-engine/badge.svg?branch=master)](https://coveralls.io/github/Ilhasoft/bothub-engine?branch=master) +[![Coverage Status](https://coveralls.io/repos/github/Ilhasoft/bothub-engine/badge.svg)](https://coveralls.io/github/Ilhasoft/bothub-engine) [![Code Climate](https://codeclimate.com/github/Ilhasoft/bothub-engine/badges/gpa.svg)](https://codeclimate.com/github/Ilhasoft/bothub-engine) [![Python Version](https://img.shields.io/badge/python-3.6-blue.svg)](https://www.python.org/) [![License GPL-3.0](https://img.shields.io/badge/license-%20GPL--3.0-yellow.svg)](https://github.com/Ilhasoft/bothub-engine/blob/master/LICENSE) From 88224200db3dd9da2b813942c2970334daf1895c Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Mon, 23 Sep 2019 10:27:59 -0300 Subject: [PATCH 167/207] Updated README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9d6f9b96..b95f8534 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ # Bothub [![Build Status](https://travis-ci.org/Ilhasoft/bothub-engine.svg?branch=master)](https://travis-ci.org/Ilhasoft/bothub-engine) -[![Coverage Status](https://coveralls.io/repos/github/Ilhasoft/bothub-engine/badge.svg)](https://coveralls.io/github/Ilhasoft/bothub-engine) +[![Coverage Status](https://coveralls.io/repos/github/Ilhasoft/bothub-engine/badge.svg?branch=master)](https://coveralls.io/github/Ilhasoft/bothub-engine?branch=master) [![Code Climate](https://codeclimate.com/github/Ilhasoft/bothub-engine/badges/gpa.svg)](https://codeclimate.com/github/Ilhasoft/bothub-engine) [![Python Version](https://img.shields.io/badge/python-3.6-blue.svg)](https://www.python.org/) [![License GPL-3.0](https://img.shields.io/badge/license-%20GPL--3.0-yellow.svg)](https://github.com/Ilhasoft/bothub-engine/blob/master/LICENSE) From 9e823f124fa4881236055c42f26a4c9b1b0f0ab4 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Fri, 27 Sep 2019 14:28:56 -0300 Subject: [PATCH 168/207] [hotfix] Save file persistor nlp train --- README.md | 1 + bothub/api/v2/nlp/views.py | 28 ++++++++++++++----- .../migrations/0035_auto_20190902_1455.py | 19 ++++++++++--- bothub/common/models.py | 7 +++-- bothub/settings.py | 5 ++-- 5 files changed, 45 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index b95f8534..b83f36df 100644 --- a/README.md +++ b/README.md @@ -88,3 +88,4 @@ You can set environment variables in your OS, write on ```.env``` file or pass v | BOTHUB_ENGINE_AWS_ACCESS_KEY_ID | ```string``` | ```None``` | | BOTHUB_ENGINE_AWS_SECRET_ACCESS_KEY | ```string``` | ```None``` | | BOTHUB_ENGINE_AWS_REGION_NAME | ```string``` | ```None``` | +| BOTHUB_ENGINE_AWS_SEND | ```bool``` | ```False``` | diff --git a/bothub/api/v2/nlp/views.py b/bothub/api/v2/nlp/views.py index b72a7344..a829f15c 100644 --- a/bothub/api/v2/nlp/views.py +++ b/bothub/api/v2/nlp/views.py @@ -1,6 +1,7 @@ import base64 import json import requests +from django.conf import settings from django.db import models from django.utils.translation import gettext_lazy as _ @@ -501,11 +502,15 @@ class RepositoryUpdateInterpretersViewSet( def retrieve(self, request, *args, **kwargs): check_auth(request) update = self.get_object() - try: - download = requests.get(update.bot_data) - bot_data = base64.b64encode(download.content) - except Exception: - bot_data = b'' + + if update.is_url: + try: + download = requests.get(update.bot_data) + bot_data = base64.b64encode(download.content) + except Exception: + bot_data = b'' + else: + bot_data = update.bot_data return Response({ 'update_id': update.id, 'repository_uuid': update.repository.uuid, @@ -519,6 +524,15 @@ def create(self, request, *args, **kwargs): RepositoryUpdate, pk=id ) - bot_data = base64.b64decode(request.data.get('bot_data')) - repository.save_training(send_bot_data_file_aws(id, bot_data)) + if settings.AWS_SEND: + bot_data = base64.b64decode(request.data.get('bot_data')) + repository.save_training( + send_bot_data_file_aws( + id, + bot_data + ), + True + ) + else: + repository.save_training(request.data.get('bot_data'), False) return Response({}) diff --git a/bothub/common/migrations/0035_auto_20190902_1455.py b/bothub/common/migrations/0035_auto_20190902_1455.py index f1cef359..72283916 100644 --- a/bothub/common/migrations/0035_auto_20190902_1455.py +++ b/bothub/common/migrations/0035_auto_20190902_1455.py @@ -1,5 +1,5 @@ # Generated by Django 2.1.5 on 2019-09-02 14:55 - +from django.conf import settings from django.db import migrations, models from bothub.utils import send_bot_data_file_aws from bothub.common.models import RepositoryUpdate @@ -7,12 +7,18 @@ def update_repository(apps, schema_editor): for update in RepositoryUpdate.objects.all().exclude(bot_data__exact=''): - url = send_bot_data_file_aws(update.pk, update.bot_data) repository_update = RepositoryUpdate.objects.get(pk=update.pk) - repository_update.bot_data = url + if settings.AWS_SEND: + bot_data = send_bot_data_file_aws(update.pk, update.bot_data) + repository_update.is_url = True + else: + bot_data = update.bot_data + repository_update.is_url = False + repository_update.bot_data = bot_data repository_update.save( update_fields=[ 'bot_data', + 'is_url', ]) print('Updating bot_data repository_update {}'.format(str(update.pk))) @@ -24,10 +30,15 @@ class Migration(migrations.Migration): ] operations = [ + migrations.AddField( + model_name='repositoryupdate', + name='is_url', + field=models.BooleanField(default=True), + ), migrations.RunPython(update_repository), migrations.AlterField( model_name='repositoryupdate', name='bot_data', - field=models.URLField(blank=True, verbose_name='bot data'), + field=models.TextField(blank=True, verbose_name='bot data'), ), ] diff --git a/bothub/common/models.py b/bothub/common/models.py index 0c593b01..10218d7c 100644 --- a/bothub/common/models.py +++ b/bothub/common/models.py @@ -484,9 +484,10 @@ class Meta: created_at = models.DateTimeField( _('created at'), auto_now_add=True) - bot_data = models.URLField( + bot_data = models.TextField( _('bot data'), blank=True) + is_url = models.BooleanField(default=True) by = models.ForeignKey( User, models.CASCADE, @@ -649,18 +650,20 @@ def start_training(self, by): 'use_name_entities', ]) - def save_training(self, bot_data): + def save_training(self, bot_data, is_url): if self.trained_at: raise RepositoryUpdateAlreadyTrained() self.trained_at = timezone.now() self.bot_data = bot_data + self.is_url = is_url self.repository.total_updates += 1 self.repository.save() self.save( update_fields=[ 'trained_at', 'bot_data', + 'is_url', ]) def get_bot_data(self): diff --git a/bothub/settings.py b/bothub/settings.py index 0f908f4b..6867cf22 100644 --- a/bothub/settings.py +++ b/bothub/settings.py @@ -40,7 +40,8 @@ BOTHUB_ENGINE_AWS_ACCESS_KEY_ID=(str, ''), BOTHUB_ENGINE_AWS_SECRET_ACCESS_KEY=(str, ''), BOTHUB_ENGINE_AWS_S3_BUCKET_NAME=(str, ''), - BOTHUB_ENGINE_AWS_REGION_NAME=(str, 'us-east-1') + BOTHUB_ENGINE_AWS_REGION_NAME=(str, 'us-east-1'), + BOTHUB_ENGINE_AWS_SEND=(bool, False) ) # Build paths inside the project like this: os.path.join(BASE_DIR, ...) @@ -275,7 +276,7 @@ # AWS - +AWS_SEND = env.bool('BOTHUB_ENGINE_AWS_SEND') AWS_ACCESS_KEY_ID = env.str('BOTHUB_ENGINE_AWS_ACCESS_KEY_ID') AWS_SECRET_ACCESS_KEY = env.str('BOTHUB_ENGINE_AWS_SECRET_ACCESS_KEY') AWS_BUCKET_NAME = env.str('BOTHUB_ENGINE_AWS_S3_BUCKET_NAME') From 0e51760f61d48335815493f780aed8f35610b5a3 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Fri, 27 Sep 2019 16:07:15 -0300 Subject: [PATCH 169/207] [hotfix] Persistor Save --- bothub/api/v2/nlp/views.py | 18 +++++++++--- .../migrations/0035_auto_20190902_1455.py | 28 ++++++------------- bothub/common/models.py | 5 +--- 3 files changed, 24 insertions(+), 27 deletions(-) diff --git a/bothub/api/v2/nlp/views.py b/bothub/api/v2/nlp/views.py index a829f15c..20e3e789 100644 --- a/bothub/api/v2/nlp/views.py +++ b/bothub/api/v2/nlp/views.py @@ -1,5 +1,7 @@ import base64 import json +import re + import requests from django.conf import settings @@ -503,7 +505,16 @@ def retrieve(self, request, *args, **kwargs): check_auth(request) update = self.get_object() - if update.is_url: + regex = re.compile( + r'^(?:http|ftp)s?://' # http:// or https:// + r'(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+(?:[A-Z]{2,6}\.?|' + r'[A-Z0-9-]{2,}\.?)|' + r'localhost|' + r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})' + r'(?::\d+)?' + r'(?:/?|[/?]\S+)$', re.IGNORECASE) + + if re.match(regex, update.bot_data) is not None: try: download = requests.get(update.bot_data) bot_data = base64.b64encode(download.content) @@ -530,9 +541,8 @@ def create(self, request, *args, **kwargs): send_bot_data_file_aws( id, bot_data - ), - True + ) ) else: - repository.save_training(request.data.get('bot_data'), False) + repository.save_training(request.data.get('bot_data')) return Response({}) diff --git a/bothub/common/migrations/0035_auto_20190902_1455.py b/bothub/common/migrations/0035_auto_20190902_1455.py index 72283916..f033d0ba 100644 --- a/bothub/common/migrations/0035_auto_20190902_1455.py +++ b/bothub/common/migrations/0035_auto_20190902_1455.py @@ -6,21 +6,16 @@ def update_repository(apps, schema_editor): - for update in RepositoryUpdate.objects.all().exclude(bot_data__exact=''): - repository_update = RepositoryUpdate.objects.get(pk=update.pk) - if settings.AWS_SEND: + if settings.AWS_SEND: + for update in RepositoryUpdate.objects.all().exclude(bot_data__exact=''): + repository_update = RepositoryUpdate.objects.get(pk=update.pk) bot_data = send_bot_data_file_aws(update.pk, update.bot_data) - repository_update.is_url = True - else: - bot_data = update.bot_data - repository_update.is_url = False - repository_update.bot_data = bot_data - repository_update.save( - update_fields=[ - 'bot_data', - 'is_url', - ]) - print('Updating bot_data repository_update {}'.format(str(update.pk))) + repository_update.bot_data = bot_data + repository_update.save( + update_fields=[ + 'bot_data', + ]) + print('Updating bot_data repository_update {}'.format(str(update.pk))) class Migration(migrations.Migration): @@ -30,11 +25,6 @@ class Migration(migrations.Migration): ] operations = [ - migrations.AddField( - model_name='repositoryupdate', - name='is_url', - field=models.BooleanField(default=True), - ), migrations.RunPython(update_repository), migrations.AlterField( model_name='repositoryupdate', diff --git a/bothub/common/models.py b/bothub/common/models.py index 10218d7c..291a8a5a 100644 --- a/bothub/common/models.py +++ b/bothub/common/models.py @@ -487,7 +487,6 @@ class Meta: bot_data = models.TextField( _('bot data'), blank=True) - is_url = models.BooleanField(default=True) by = models.ForeignKey( User, models.CASCADE, @@ -650,20 +649,18 @@ def start_training(self, by): 'use_name_entities', ]) - def save_training(self, bot_data, is_url): + def save_training(self, bot_data): if self.trained_at: raise RepositoryUpdateAlreadyTrained() self.trained_at = timezone.now() self.bot_data = bot_data - self.is_url = is_url self.repository.total_updates += 1 self.repository.save() self.save( update_fields=[ 'trained_at', 'bot_data', - 'is_url', ]) def get_bot_data(self): From 8d6340d0fe891513b72b6d8a8df8eae0035ca8ed Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Tue, 1 Oct 2019 09:59:15 -0300 Subject: [PATCH 170/207] Updated imports --- bothub/api/v2/nlp/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bothub/api/v2/nlp/views.py b/bothub/api/v2/nlp/views.py index 20e3e789..daab0290 100644 --- a/bothub/api/v2/nlp/views.py +++ b/bothub/api/v2/nlp/views.py @@ -1,8 +1,8 @@ import base64 import json import re - import requests + from django.conf import settings from django.db import models From f2d7cb4f83694fa9a360a1381b7698aa73e2b257 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Tue, 1 Oct 2019 10:00:31 -0300 Subject: [PATCH 171/207] Updated imports --- bothub/api/v2/nlp/views.py | 1 - 1 file changed, 1 deletion(-) diff --git a/bothub/api/v2/nlp/views.py b/bothub/api/v2/nlp/views.py index daab0290..5a947ee5 100644 --- a/bothub/api/v2/nlp/views.py +++ b/bothub/api/v2/nlp/views.py @@ -4,7 +4,6 @@ import requests from django.conf import settings - from django.db import models from django.utils.translation import gettext_lazy as _ from django.shortcuts import get_object_or_404 From dafd64bdc217dbed674f5fbf4e238470bca7b7fe Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Tue, 1 Oct 2019 10:33:39 -0300 Subject: [PATCH 172/207] Installed black package --- Pipfile | 1 + Pipfile.lock | 88 ++++++++++++++++++++++++++++++++++++---------------- 2 files changed, 63 insertions(+), 26 deletions(-) diff --git a/Pipfile b/Pipfile index 611dd795..9e440481 100644 --- a/Pipfile +++ b/Pipfile @@ -24,6 +24,7 @@ boto3 = "*" coverage = "*" ipython = "*" autopep8 = "*" +black = "==19.3b0" [requires] python_version = "3.6" diff --git a/Pipfile.lock b/Pipfile.lock index f4a62335..574674e8 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "1fbd5293399ec55bf270b7e84723abb49d41b54bd77625cbb37e1062db428ef5" + "sha256": "de9033e279afa3aa5dfb7a263f9e5b855543712b0cd5a20abd1cba5a45564dd6" }, "pipfile-spec": 6, "requires": { @@ -18,18 +18,18 @@ "default": { "boto3": { "hashes": [ - "sha256:0e4d047feb4d7d701e9b2107f10bb8d674952243385cd35d0b413a273c299751", - "sha256:67f957389cf56fb4c24c1093c6d58baebe6cf18139f6dca0f8a177239b0a4f8c" + "sha256:5ff78c697d8009b9fe9808baea60660f0a07be666fb7c65fc4c11756f568124e", + "sha256:d01314496080ac82ddff3d1b2c6ad542d89bfcb100b7a0e8aaf2d6aef99775c6" ], "index": "pypi", - "version": "==1.9.232" + "version": "==1.9.239" }, "botocore": { "hashes": [ - "sha256:724d2349198c6f15f3cee0c0e4d33ecf4435e6d0db311bb79a3a28f6cf5a4090", - "sha256:a57a8fd0145c68e31bb4baab549b27a12f6695068c8dd5f2901d8dc06572dbeb" + "sha256:14ff881779776a5b08e4bb8d7e0cd6ca86e36fc80decc536d605c406fb81c993", + "sha256:5df4a8f8bb579daed58368d6c15cdd72455bfee7dc86be243e2ef4dff5ba1177" ], - "version": "==1.12.232" + "version": "==1.12.239" }, "certifi": { "hashes": [ @@ -292,27 +292,27 @@ }, "ruamel.yaml.clib": { "hashes": [ - "sha256:0bbe19d3e099f8ba384e1846e6b54f245f58aeec8700edbbf9abb87afa54fd82", - "sha256:2f38024592613f3a8772bbc2904be027d9abf463518ba145f2d0c8e6da27009f", - "sha256:44449b3764a3f75815eea8ae5930b98e8326be64a90b0f782747318f861abfe0", - "sha256:5710be9a357801c31c1eaa37b9bc92d38176d785af5b2f0c9751385c5dc9659a", - "sha256:5a089acb6833ed5f412e24cbe3e665683064c1429824d2819137b5ade54435c3", - "sha256:6143386ddd61599ea081c012a69a16e5bdd7b3c6c231bd039534365a48940f30", - "sha256:6726aaf851f5f9e4cbdd3e1e414bc700bdd39220e8bc386415fd41c87b1b53c2", - "sha256:68fbc3b5d94d145a391452f886ae5fca240cb7e3ab6bd66e1a721507cdaac28a", - "sha256:75ebddf99ba9e0b48f32b5bdcf9e5a2b84c017da9e0db7bf11995fa414aa09cd", - "sha256:79948a6712baa686773a43906728e20932c923f7b2a91be7347993be2d745e55", - "sha256:8a2dd8e8b08d369558cade05731172c4b5e2f4c5097762c6b352bd28fd9f9dc4", - "sha256:c747acdb5e8c242ab2280df6f0c239e62838af4bee647031d96b3db2f9cefc04", - "sha256:cadc8eecd27414dca30366b2535cb5e3f3b47b4e2d6be7a0b13e4e52e459ff9f", - "sha256:cee86ecc893a6a8ecaa7c6a9c2d06f75f614176210d78a5f155f8e78d6989509", - "sha256:e59af39e895aff28ee5f55515983cab3466d1a029c91c04db29da1c0f09cf333", - "sha256:eee7ecd2eee648884fae6c51ae50c814acdcc5d6340dc96c970158aebcd25ac6", - "sha256:ef8d4522d231cb9b29f6cdd0edc8faac9d9715c60dc7becbd6eb82c915a98e5b", - "sha256:f504d45230cc9abf2810623b924ae048b224a90adb01f97db4e766cfdda8e6eb" + "sha256:1e77424825caba5553bbade750cec2277ef130647d685c2b38f68bc03453bac6", + "sha256:392b7c371312abf27fb549ec2d5e0092f7ef6e6c9f767bfb13e83cb903aca0fd", + "sha256:4d55386129291b96483edcb93b381470f7cd69f97585829b048a3d758d31210a", + "sha256:550168c02d8de52ee58c3d8a8193d5a8a9491a5e7b2462d27ac5bf63717574c9", + "sha256:57933a6986a3036257ad7bf283529e7c19c2810ff24c86f4a0cfeb49d2099919", + "sha256:615b0396a7fad02d1f9a0dcf9f01202bf9caefee6265198f252c865f4227fcc6", + "sha256:77556a7aa190be9a2bd83b7ee075d3df5f3c5016d395613671487e79b082d784", + "sha256:7aee724e1ff424757b5bd8f6c5bbdb033a570b2b4683b17ace4dbe61a99a657b", + "sha256:8073c8b92b06b572e4057b583c3d01674ceaf32167801fe545a087d7a1e8bf52", + "sha256:9c6d040d0396c28d3eaaa6cb20152cb3b2f15adf35a0304f4f40a3cf9f1d2448", + "sha256:a0ff786d2a7dbe55f9544b3f6ebbcc495d7e730df92a08434604f6f470b899c5", + "sha256:b1b7fcee6aedcdc7e62c3a73f238b3d080c7ba6650cd808bce8d7761ec484070", + "sha256:b66832ea8077d9b3f6e311c4a53d06273db5dc2db6e8a908550f3c14d67e718c", + "sha256:d0d3ac228c9bbab08134b4004d748cf9f8743504875b3603b3afbb97e3472947", + "sha256:d10e9dd744cf85c219bf747c75194b624cc7a94f0c80ead624b06bfa9f61d3bc", + "sha256:ea4362548ee0cbc266949d8a441238d9ad3600ca9910c3fe4e82ee3a50706973", + "sha256:ed5b3698a2bb241b7f5cbbe277eaa7fe48b07a58784fba4f75224fd066d253ad", + "sha256:f9dcc1ae73f36e8059589b601e8e4776b9976effd76c21ad6a855a74318efd6e" ], "markers": "platform_python_implementation == 'CPython' and python_version < '3.8'", - "version": "==0.1.2" + "version": "==0.2.0" }, "s3transfer": { "hashes": [ @@ -354,6 +354,13 @@ } }, "develop": { + "appdirs": { + "hashes": [ + "sha256:9e5896d1372858f8dd3344faf4e5014d21849c756c8d5701f78f8a103b372d92", + "sha256:d8b24664561d0d34ddfaec54636d502d7cea6e29c3eaf68f3df6180863e2166e" + ], + "version": "==1.4.3" + }, "appnope": { "hashes": [ "sha256:5b26757dc6f79a3b7dc9fab95359328d5747fcb2409d331ea66d0272b90ab2a0", @@ -362,6 +369,13 @@ "markers": "sys_platform == 'darwin'", "version": "==0.1.0" }, + "attrs": { + "hashes": [ + "sha256:69c0dbf2ed392de1cb5ec704444b08a5ef81680a61cb899dc08127123af36a79", + "sha256:f0b870f674851ecbfbbbd364d6b5cbdff9dcedbc7f3f5e18a6891057f21fe399" + ], + "version": "==19.1.0" + }, "autopep8": { "hashes": [ "sha256:4d8eec30cc81bc5617dbf1218201d770dc35629363547f17577c61683ccfb3ee" @@ -376,6 +390,21 @@ ], "version": "==0.1.0" }, + "black": { + "hashes": [ + "sha256:09a9dcb7c46ed496a9850b76e4e825d6049ecd38b611f1224857a79bd985a8cf", + "sha256:68950ffd4d9169716bcb8719a56c07a2f4485354fec061cdd5910aa07369731c" + ], + "index": "pypi", + "version": "==19.3b0" + }, + "click": { + "hashes": [ + "sha256:2335065e6395b9e67ca716de5f7526736bfa6ceead690adf616d925bdc622b13", + "sha256:5b94b49521f6456670fdb30cd82a4eca9412788a93fa6dd6df72c94d5a8ff2d7" + ], + "version": "==7.0" + }, "coverage": { "hashes": [ "sha256:08907593569fe59baca0bf152c43f3863201efb6113ecb38ce7e97ce339805a6", @@ -530,6 +559,13 @@ ], "version": "==1.12.0" }, + "toml": { + "hashes": [ + "sha256:229f81c57791a41d65e399fc06bf0848bab550a9dfd5ed66df18ce5f05e73d5c", + "sha256:235682dd292d5899d361a811df37e04a8828a5b1da3115886b73cf81ebc9100e" + ], + "version": "==0.10.0" + }, "traitlets": { "hashes": [ "sha256:9c4bd2d267b7153df9152698efb1050a5d84982d3384a37b2c1f7723ba3e7835", From 7b1196b74dc747afa8e2095568f0ec46cbefd6e1 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Tue, 1 Oct 2019 10:33:51 -0300 Subject: [PATCH 173/207] Updated config flake8 for black --- .flake8 | 1 + 1 file changed, 1 insertion(+) diff --git a/.flake8 b/.flake8 index 135deedd..7594c5e1 100644 --- a/.flake8 +++ b/.flake8 @@ -1,4 +1,5 @@ [flake8] +max-line-length = 119 exclude = ./env migrations From d202d3114b85caed67510412d771104147c468c5 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Tue, 1 Oct 2019 10:34:10 -0300 Subject: [PATCH 174/207] Updated project PEP8 with black --- bothub/api/v1/apps.py | 2 +- bothub/api/v1/fields.py | 20 +- bothub/api/v1/metadata.py | 22 +- bothub/api/v1/routers.py | 133 +- bothub/api/v1/serializers/__init__.py | 8 +- bothub/api/v1/serializers/category.py | 6 +- bothub/api/v1/serializers/example.py | 150 +- bothub/api/v1/serializers/repository.py | 161 +- bothub/api/v1/serializers/request.py | 58 +- bothub/api/v1/serializers/translate.py | 90 +- bothub/api/v1/serializers/update.py | 23 +- bothub/api/v1/serializers/user.py | 57 +- bothub/api/v1/tests/test_authorization.py | 196 +- bothub/api/v1/tests/test_categories.py | 29 +- bothub/api/v1/tests/test_example.py | 708 +++--- bothub/api/v1/tests/test_examples.py | 282 +-- bothub/api/v1/tests/test_repository.py | 780 +++--- bothub/api/v1/tests/test_request.py | 237 +- bothub/api/v1/tests/test_translate.py | 545 ++-- bothub/api/v1/tests/test_updates.py | 66 +- bothub/api/v1/tests/test_user.py | 323 +-- bothub/api/v1/tests/utils.py | 8 +- bothub/api/v1/validators.py | 99 +- bothub/api/v1/views.py | 902 +++---- bothub/api/v2/__init__.py | 4 +- bothub/api/v2/account/serializers.py | 84 +- bothub/api/v2/account/views.py | 89 +- bothub/api/v2/evaluate/filters.py | 76 +- bothub/api/v2/evaluate/permissions.py | 13 +- bothub/api/v2/evaluate/serializers.py | 158 +- bothub/api/v2/evaluate/validators.py | 30 +- bothub/api/v2/evaluate/views.py | 161 +- bothub/api/v2/example/permissions.py | 5 +- bothub/api/v2/example/serializers.py | 69 +- bothub/api/v2/examples/filters.py | 83 +- bothub/api/v2/examples/views.py | 24 +- bothub/api/v2/fields.py | 20 +- bothub/api/v2/metadata.py | 140 +- bothub/api/v2/nlp/views.py | 417 ++-- bothub/api/v2/repository/filters.py | 54 +- bothub/api/v2/repository/permissions.py | 8 +- bothub/api/v2/repository/serializers.py | 536 ++-- bothub/api/v2/repository/validators.py | 51 +- bothub/api/v2/repository/views.py | 343 ++- bothub/api/v2/routers.py | 144 +- bothub/api/v2/tests/test_account.py | 345 +-- bothub/api/v2/tests/test_evaluate.py | 552 ++--- bothub/api/v2/tests/test_examples.py | 328 +-- bothub/api/v2/tests/test_nlp.py | 272 +- bothub/api/v2/tests/test_repository.py | 2184 +++++++---------- bothub/api/v2/tests/test_translation.py | 550 ++--- bothub/api/v2/tests/utils.py | 8 +- bothub/api/v2/translation/filters.py | 32 +- bothub/api/v2/translation/serializers.py | 91 +- bothub/api/v2/translation/validators.py | 64 +- bothub/api/v2/translation/views.py | 20 +- bothub/api/v2/urls.py | 7 +- bothub/api/v2/views.py | 2 +- bothub/authentication/apps.py | 2 +- .../authentication/migrations/0001_initial.py | 103 +- .../migrations/0002_auto_20180315_1343.py | 54 +- .../migrations/0003_auto_20180522_1705.py | 17 +- .../migrations/0004_auto_20180605_1357.py | 24 +- .../migrations/0005_auto_20180620_2059.py | 25 +- bothub/authentication/models.py | 118 +- bothub/authentication/tests.py | 17 +- bothub/common/admin.py | 63 +- bothub/common/apps.py | 2 +- bothub/common/languages.py | 158 +- .../commands/fill_db_using_fake_data.py | 221 +- bothub/common/migrations/0001_initial.py | 391 ++- .../migrations/0002_auto_20180315_1343.py | 273 ++- .../migrations/0003_auto_20180503_1223.py | 15 +- .../migrations/0004_auto_20180514_1129.py | 14 +- ...torytranslatedexample_repository_update.py | 32 +- .../0006_repositoryupdate_failed_at.py | 12 +- ..._repositorytranslatedexample_created_at.py | 16 +- .../migrations/0008_auto_20180529_1340.py | 14 +- .../migrations/0009_auto_20180601_1348.py | 47 +- .../migrations/0010_auto_20180611_1123.py | 56 +- .../0011_repositoryauthorization_role.py | 16 +- .../migrations/0012_auto_20180703_1931.py | 53 +- .../migrations/0013_auto_20180706_1212.py | 16 +- .../migrations/0014_auto_20180709_1909.py | 36 +- .../migrations/0015_auto_20180712_2130.py | 17 +- .../migrations/0016_auto_20180712_2131.py | 16 +- .../migrations/0017_auto_20180712_2131.py | 17 +- .../migrations/0018_auto_20180725_1305.py | 77 +- .../migrations/0019_auto_20180725_1657.py | 71 +- .../migrations/0020_auto_20180813_1320.py | 24 +- .../migrations/0021_auto_20180921_1259.py | 26 +- .../0022_repositoryupdate_training_log.py | 14 +- ...epository_use_language_model_featurizer.py | 16 +- ...oryupdate_use_language_model_featurizer.py | 10 +- .../migrations/0025_auto_20181003_1911.py | 18 +- .../migrations/0026_auto_20181010_1704.py | 16 +- .../0027_repositorycategory_icon.py | 14 +- .../migrations/0028_auto_20190121_1250.py | 46 +- .../migrations/0029_auto_20190126_0247.py | 34 +- .../migrations/0030_auto_20190327_2003.py | 18 +- .../migrations/0031_auto_20190502_1732.py | 358 ++- .../0032_repository_total_updates.py | 14 +- .../migrations/0033_auto_20190816_2030.py | 17 +- .../migrations/0034_repository_nlp_server.py | 12 +- .../migrations/0035_auto_20190902_1455.py | 19 +- bothub/common/models.py | 1156 ++++----- bothub/common/tests.py | 1061 ++++---- bothub/common/views.py | 2 +- bothub/health/apps.py | 2 +- bothub/health/checks.py | 27 +- bothub/health/views.py | 33 +- bothub/settings.py | 254 +- bothub/urls.py | 134 +- bothub/utils.py | 29 +- 114 files changed, 7609 insertions(+), 9607 deletions(-) diff --git a/bothub/api/v1/apps.py b/bothub/api/v1/apps.py index d87006dd..14b89a82 100644 --- a/bothub/api/v1/apps.py +++ b/bothub/api/v1/apps.py @@ -2,4 +2,4 @@ class ApiConfig(AppConfig): - name = 'api' + name = "api" diff --git a/bothub/api/v1/fields.py b/bothub/api/v1/fields.py index b41552d3..091c04b0 100644 --- a/bothub/api/v1/fields.py +++ b/bothub/api/v1/fields.py @@ -14,7 +14,7 @@ class TextField(serializers.CharField): class PasswordField(serializers.CharField): def __init__(self, *args, **kwargs): - kwargs.pop('trim_whitespace', None) + kwargs.pop("trim_whitespace", None) super().__init__(trim_whitespace=False, **kwargs) @@ -24,16 +24,17 @@ class EntityText(serializers.CharField): class EntityValueField(serializers.CharField): def __init__(self, *args, validators=[], **kwargs): - kwargs.pop('max_length', 0) - kwargs.pop('help_text', '') + kwargs.pop("max_length", 0) + kwargs.pop("help_text", "") - value_field = RepositoryEntity._meta.get_field('value') + value_field = RepositoryEntity._meta.get_field("value") super().__init__( *args, max_length=value_field.max_length, validators=(validators + value_field.validators), - **kwargs) + **kwargs + ) def to_representation(self, obj): return obj.value @@ -41,16 +42,17 @@ def to_representation(self, obj): class LabelValueField(serializers.CharField): def __init__(self, *args, validators=[], **kwargs): - kwargs.pop('max_length', 0) - kwargs.pop('help_text', '') + kwargs.pop("max_length", 0) + kwargs.pop("help_text", "") - value_field = RepositoryEntityLabel._meta.get_field('value') + value_field = RepositoryEntityLabel._meta.get_field("value") super().__init__( *args, max_length=value_field.max_length, validators=(validators + value_field.validators), - **kwargs) + **kwargs + ) def to_representation(self, obj): return obj.value diff --git a/bothub/api/v1/metadata.py b/bothub/api/v1/metadata.py index 4272d614..5eab5cd2 100644 --- a/bothub/api/v1/metadata.py +++ b/bothub/api/v1/metadata.py @@ -13,21 +13,21 @@ class Metadata(SimpleMetadata): def get_field_info(self, field): field_info = super().get_field_info(field) if isinstance(field, ModelMultipleChoiceField): - field_info['choices'] = [ + field_info["choices"] = [ { - 'value': choice_value, - 'display_name': force_text(choice_name, strings_only=True) + "value": choice_value, + "display_name": force_text(choice_name, strings_only=True), } for choice_value, choice_name in field.choices.items() ] - if hasattr(field, 'style'): - field_info['style'] = field.style + if hasattr(field, "style"): + field_info["style"] = field.style return field_info -Metadata.label_lookup[ModelMultipleChoiceField] = 'multiple choice' -Metadata.label_lookup[TextField] = 'text' -Metadata.label_lookup[PasswordField] = 'password' -Metadata.label_lookup[serializers.HiddenField] = 'hidden' -Metadata.label_lookup[NewRepositoryExampleEntitySerializer] = 'entity' -Metadata.label_lookup[EntityText] = 'entity text' +Metadata.label_lookup[ModelMultipleChoiceField] = "multiple choice" +Metadata.label_lookup[TextField] = "text" +Metadata.label_lookup[PasswordField] = "password" +Metadata.label_lookup[serializers.HiddenField] = "hidden" +Metadata.label_lookup[NewRepositoryExampleEntitySerializer] = "entity" +Metadata.label_lookup[EntityText] = "entity text" diff --git a/bothub/api/v1/routers.py b/bothub/api/v1/routers.py index d33a0e16..9b8e2c52 100644 --- a/bothub/api/v1/routers.py +++ b/bothub/api/v1/routers.py @@ -34,16 +34,16 @@ class Router(routers.SimpleRouter): # Generated using @action decorator # on methods of the viewset. routers.DynamicRoute( - url=r'^{prefix}/{url_path}{trailing_slash}$', - name='{basename}-{url_name}', + url=r"^{prefix}/{url_path}{trailing_slash}$", + name="{basename}-{url_name}", detail=True, initkwargs={}, ), # Dynamically generated detail routes. # Generated using @action decorator on methods of the viewset. routers.DynamicRoute( - url=r'^{prefix}/{lookup}/{url_path}{trailing_slash}$', - name='{basename}-{url_name}', + url=r"^{prefix}/{lookup}/{url_path}{trailing_slash}$", + name="{basename}-{url_name}", detail=True, initkwargs={}, ), @@ -51,79 +51,80 @@ class Router(routers.SimpleRouter): def get_routes(self, viewset): ret = super().get_routes(viewset) - lookup_field = getattr(viewset, 'lookup_field', None) + lookup_field = getattr(viewset, "lookup_field", None) if lookup_field: # List route. - ret.append(routers.Route( - url=r'^{prefix}{trailing_slash}$', - mapping={ - 'get': 'list', - 'post': 'create' - }, - name='{basename}-list', - detail=False, - initkwargs={'suffix': 'List'}, - )) + ret.append( + routers.Route( + url=r"^{prefix}{trailing_slash}$", + mapping={"get": "list", "post": "create"}, + name="{basename}-list", + detail=False, + initkwargs={"suffix": "List"}, + ) + ) - detail_url_regex = r'^{prefix}/{lookup}{trailing_slash}$' + detail_url_regex = r"^{prefix}/{lookup}{trailing_slash}$" if not lookup_field: - detail_url_regex = r'^{prefix}{trailing_slash}$' + detail_url_regex = r"^{prefix}{trailing_slash}$" # Detail route. - ret.append(routers.Route( - url=detail_url_regex, - mapping={ - 'get': 'retrieve', - 'put': 'update', - 'patch': 'partial_update', - 'delete': 'destroy' - }, - name='{basename}-detail', - detail=True, - initkwargs={'suffix': 'Instance'} - )) + ret.append( + routers.Route( + url=detail_url_regex, + mapping={ + "get": "retrieve", + "put": "update", + "patch": "partial_update", + "delete": "destroy", + }, + name="{basename}-detail", + detail=True, + initkwargs={"suffix": "Instance"}, + ) + ) return ret - def get_lookup_regex(self, viewset, lookup_prefix=''): - lookup_fields = getattr(viewset, 'lookup_fields', None) + def get_lookup_regex(self, viewset, lookup_prefix=""): + lookup_fields = getattr(viewset, "lookup_fields", None) if lookup_fields: - base_regex = '(?P<{lookup_prefix}{lookup_url_kwarg}>[^/.]+)' - return '/'.join(map( - lambda x: base_regex.format( - lookup_prefix=lookup_prefix, - lookup_url_kwarg=x), - lookup_fields)) + base_regex = "(?P<{lookup_prefix}{lookup_url_kwarg}>[^/.]+)" + return "/".join( + map( + lambda x: base_regex.format( + lookup_prefix=lookup_prefix, lookup_url_kwarg=x + ), + lookup_fields, + ) + ) return super().get_lookup_regex(viewset, lookup_prefix) router = Router() -router.register('repository/new', NewRepositoryViewSet) -router.register('search-repositories', SearchRepositoriesViewSet) -router.register('repository', RepositoryViewSet) -router.register('example/new', NewRepositoryExampleViewSet) -router.register('example', RepositoryExampleViewSet) -router.register('translate-example', NewRepositoryTranslatedExampleViewSet) -router.register('translation', RepositoryTranslatedExampleViewSet) -router.register('examples', RepositoryExamplesViewSet) -router.register('register', RegisterUserViewSet) -router.register('login', LoginViewSet) -router.register('change-password', ChangePasswordViewSet) -router.register('forgot-password', RequestResetPassword) -router.register('reset-password', ResetPassword) -router.register('my-profile', MyUserProfileViewSet) -router.register('user-profile', UserProfileViewSet) -router.register('categories', Categories) -router.register('repositories', RepositoriesViewSet) -router.register('translations', TranslationsViewSet) -router.register('authorizations', RepositoryAuthorizationViewSet) -router.register('authorization-role', - RepositoryAuthorizationRoleViewSet) -router.register('search-user', SearchUserViewSet) -router.register('request-authorization', RequestAuthorizationViewSet) -router.register('authorization-requests', - RepositoryAuthorizationRequestsViewSet) -router.register('review-authorization-request', - ReviewAuthorizationRequestViewSet) -router.register('entities', RepositoryEntitiesViewSet) -router.register('updates', RepositoryUpdatesViewSet) +router.register("repository/new", NewRepositoryViewSet) +router.register("search-repositories", SearchRepositoriesViewSet) +router.register("repository", RepositoryViewSet) +router.register("example/new", NewRepositoryExampleViewSet) +router.register("example", RepositoryExampleViewSet) +router.register("translate-example", NewRepositoryTranslatedExampleViewSet) +router.register("translation", RepositoryTranslatedExampleViewSet) +router.register("examples", RepositoryExamplesViewSet) +router.register("register", RegisterUserViewSet) +router.register("login", LoginViewSet) +router.register("change-password", ChangePasswordViewSet) +router.register("forgot-password", RequestResetPassword) +router.register("reset-password", ResetPassword) +router.register("my-profile", MyUserProfileViewSet) +router.register("user-profile", UserProfileViewSet) +router.register("categories", Categories) +router.register("repositories", RepositoriesViewSet) +router.register("translations", TranslationsViewSet) +router.register("authorizations", RepositoryAuthorizationViewSet) +router.register("authorization-role", RepositoryAuthorizationRoleViewSet) +router.register("search-user", SearchUserViewSet) +router.register("request-authorization", RequestAuthorizationViewSet) +router.register("authorization-requests", RepositoryAuthorizationRequestsViewSet) +router.register("review-authorization-request", ReviewAuthorizationRequestViewSet) +router.register("entities", RepositoryEntitiesViewSet) +router.register("updates", RepositoryUpdatesViewSet) diff --git a/bothub/api/v1/serializers/__init__.py b/bothub/api/v1/serializers/__init__.py index 1e983768..e57432e3 100644 --- a/bothub/api/v1/serializers/__init__.py +++ b/bothub/api/v1/serializers/__init__.py @@ -8,9 +8,7 @@ RepositoryAuthorizationRoleSerializer, ) -from .category import ( # noqa: F401 - RepositoryCategorySerializer, -) +from .category import RepositoryCategorySerializer # noqa: F401 from .example import ( # noqa: F401 RepositoryExampleEntitySerializer, @@ -40,6 +38,4 @@ ReviewAuthorizationRequestSerializer, ) -from .update import ( # noqa: F401 - RepositoryUpdateSerializer, -) +from .update import RepositoryUpdateSerializer # noqa: F401 diff --git a/bothub/api/v1/serializers/category.py b/bothub/api/v1/serializers/category.py index 07a1437f..d914f248 100644 --- a/bothub/api/v1/serializers/category.py +++ b/bothub/api/v1/serializers/category.py @@ -6,9 +6,5 @@ class RepositoryCategorySerializer(serializers.ModelSerializer): class Meta: model = RepositoryCategory - fields = [ - 'id', - 'name', - 'icon', - ] + fields = ["id", "name", "icon"] ref_name = None diff --git a/bothub/api/v1/serializers/example.py b/bothub/api/v1/serializers/example.py index 938af5bf..890d83b7 100644 --- a/bothub/api/v1/serializers/example.py +++ b/bothub/api/v1/serializers/example.py @@ -25,23 +25,22 @@ class RepositoryExampleEntitySerializer(serializers.ModelSerializer): class Meta: model = RepositoryExampleEntity fields = [ - 'id', - 'repository_example', - 'start', - 'end', - 'entity', - 'label', - 'created_at', - 'value', + "id", + "repository_example", + "start", + "end", + "entity", + "label", + "created_at", + "value", ] ref_name = None repository_example = serializers.PrimaryKeyRelatedField( queryset=RepositoryExample.objects, - validators=[ - CanContributeInRepositoryExampleValidator(), - ], - help_text=_('Example\'s ID')) + validators=[CanContributeInRepositoryExampleValidator()], + help_text=_("Example's ID"), + ) entity = serializers.SerializerMethodField() label = serializers.SerializerMethodField() @@ -57,38 +56,30 @@ def get_label(self, obj): class NewRepositoryExampleEntitySerializer(serializers.ModelSerializer): class Meta: model = RepositoryExampleEntity - fields = [ - 'repository_example', - 'start', - 'end', - 'entity', - 'label', - ] + fields = ["repository_example", "start", "end", "entity", "label"] ref_name = None repository_example = serializers.PrimaryKeyRelatedField( - queryset=RepositoryExample.objects, - required=False) + queryset=RepositoryExample.objects, required=False + ) entity = EntityValueField() - label = LabelValueField( - allow_blank=True, - required=False) + label = LabelValueField(allow_blank=True, required=False) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.validators.append(EntityNotEqualLabelValidator()) def create(self, validated_data): - repository_example = validated_data.pop('repository_example', None) + repository_example = validated_data.pop("repository_example", None) assert repository_example - label = validated_data.pop('label', empty) + label = validated_data.pop("label", empty) example_entity = self.Meta.model.objects.create( - repository_example=repository_example, - **validated_data) + repository_example=repository_example, **validated_data + ) if label is not empty: example_entity.entity.set_label(label) - example_entity.entity.save(update_fields=['label']) + example_entity.entity.save(update_fields=["label"]) return example_entity @@ -96,28 +87,21 @@ class RepositoryExampleSerializer(serializers.ModelSerializer): class Meta: model = RepositoryExample fields = [ - 'id', - 'repository_update', - 'deleted_in', - 'text', - 'intent', - 'language', - 'created_at', - 'entities', - 'translations', - ] - read_only_fields = [ - 'repository_update', - 'deleted_in', + "id", + "repository_update", + "deleted_in", + "text", + "intent", + "language", + "created_at", + "entities", + "translations", ] + read_only_fields = ["repository_update", "deleted_in"] ref_name = None - entities = RepositoryExampleEntitySerializer( - many=True, - read_only=True) - translations = RepositoryTranslatedExampleSerializer( - many=True, - read_only=True) + entities = RepositoryExampleEntitySerializer(many=True, read_only=True) + translations = RepositoryTranslatedExampleSerializer(many=True, read_only=True) language = serializers.SerializerMethodField() def get_language(self, obj): @@ -128,37 +112,33 @@ class NewRepositoryExampleSerializer(serializers.ModelSerializer): class Meta: model = RepositoryExample fields = [ - 'id', - 'repository', - 'repository_update', - 'text', - 'language', - 'intent', - 'entities', + "id", + "repository", + "repository_update", + "text", + "language", + "intent", + "entities", ] ref_name = None - id = serializers.PrimaryKeyRelatedField( - read_only=True, - style={'show': False}) - text = EntityText(style={'entities_field': 'entities'}) + id = serializers.PrimaryKeyRelatedField(read_only=True, style={"show": False}) + text = EntityText(style={"entities_field": "entities"}) repository = serializers.PrimaryKeyRelatedField( queryset=Repository.objects, - validators=[ - CanContributeInRepositoryValidator(), - ], + validators=[CanContributeInRepositoryValidator()], write_only=True, - style={'show': False}) + style={"show": False}, + ) repository_update = serializers.PrimaryKeyRelatedField( - read_only=True, - style={'show': False}) + read_only=True, style={"show": False} + ) language = serializers.ChoiceField( - languages.LANGUAGE_CHOICES, - allow_blank=True, - required=False) + languages.LANGUAGE_CHOICES, allow_blank=True, required=False + ) entities = NewRepositoryExampleEntitySerializer( - many=True, - style={'text_field': 'text'}) + many=True, style={"text_field": "text"} + ) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) @@ -166,20 +146,19 @@ def __init__(self, *args, **kwargs): self.validators.append(IntentAndSentenceNotExistsValidator()) def create(self, validated_data): - entities_data = validated_data.pop('entities') - repository = validated_data.pop('repository') + entities_data = validated_data.pop("entities") + repository = validated_data.pop("repository") try: - language = validated_data.pop('language') + language = validated_data.pop("language") except KeyError: language = None repository_update = repository.current_update(language or None) - validated_data.update({'repository_update': repository_update}) + validated_data.update({"repository_update": repository_update}) example = self.Meta.model.objects.create(**validated_data) for entity_data in entities_data: - entity_data.update({'repository_example': example.pk}) - entity_serializer = NewRepositoryExampleEntitySerializer( - data=entity_data) + entity_data.update({"repository_example": example.pk}) + entity_serializer = NewRepositoryExampleEntitySerializer(data=entity_data) entity_serializer.is_valid(raise_exception=True) entity_serializer.save() return example @@ -188,11 +167,7 @@ def create(self, validated_data): class RepositoryEntitySerializer(serializers.ModelSerializer): class Meta: model = RepositoryEntity - fields = [ - 'repository', - 'value', - 'label', - ] + fields = ["repository", "value", "label"] ref_name = None label = serializers.SerializerMethodField() @@ -206,15 +181,10 @@ def get_label(self, obj): class RepositoryEntityLabelSerializer(serializers.ModelSerializer): class Meta: model = RepositoryEntityLabel - fields = [ - 'repository', - 'value', - 'entities', - ] + fields = ["repository", "value", "entities"] ref_name = None repository = serializers.StringRelatedField(read_only=True) entities = serializers.SlugRelatedField( - many=True, - slug_field='value', - read_only=True) + many=True, slug_field="value", read_only=True + ) diff --git a/bothub/api/v1/serializers/repository.py b/bothub/api/v1/serializers/repository.py index 7a5c6b92..9846e916 100644 --- a/bothub/api/v1/serializers/repository.py +++ b/bothub/api/v1/serializers/repository.py @@ -20,34 +20,33 @@ class NewRepositorySerializer(serializers.ModelSerializer): class Meta: model = Repository fields = [ - 'uuid', - 'owner', - 'name', - 'slug', - 'language', - 'algorithm', - 'use_competing_intents', - 'use_name_entities', - 'categories', - 'description', - 'is_private', + "uuid", + "owner", + "name", + "slug", + "language", + "algorithm", + "use_competing_intents", + "use_name_entities", + "categories", + "description", + "is_private", ] ref_name = None - uuid = serializers.ReadOnlyField( - style={'show': False}) + uuid = serializers.ReadOnlyField(style={"show": False}) owner = serializers.HiddenField(default=serializers.CurrentUserDefault()) - language = serializers.ChoiceField( - LANGUAGE_CHOICES, - label=_('Language')) + language = serializers.ChoiceField(LANGUAGE_CHOICES, label=_("Language")) categories = ModelMultipleChoiceField( child_relation=serializers.PrimaryKeyRelatedField( - queryset=RepositoryCategory.objects.all()), + queryset=RepositoryCategory.objects.all() + ), allow_empty=False, - help_text=Repository.CATEGORIES_HELP_TEXT) + help_text=Repository.CATEGORIES_HELP_TEXT, + ) description = TextField( - allow_blank=True, - help_text=Repository.DESCRIPTION_HELP_TEXT) + allow_blank=True, help_text=Repository.DESCRIPTION_HELP_TEXT + ) class EditRepositorySerializer(NewRepositorySerializer): @@ -58,47 +57,44 @@ class RepositorySerializer(serializers.ModelSerializer): class Meta: model = Repository fields = [ - 'uuid', - 'owner', - 'owner__nickname', - 'name', - 'slug', - 'language', - 'available_languages', - 'algorithm', - 'use_language_model_featurizer', - 'use_competing_intents', - 'use_name_entities', - 'categories', - 'categories_list', - 'description', - 'is_private', - 'intents', - 'entities', - 'labels', - 'labels_list', - 'examples__count', - 'authorization', - 'available_request_authorization', - 'request_authorization', - 'ready_for_train', - 'requirements_to_train', - 'languages_ready_for_train', - 'languages_warnings', - 'created_at', + "uuid", + "owner", + "owner__nickname", + "name", + "slug", + "language", + "available_languages", + "algorithm", + "use_language_model_featurizer", + "use_competing_intents", + "use_name_entities", + "categories", + "categories_list", + "description", + "is_private", + "intents", + "entities", + "labels", + "labels_list", + "examples__count", + "authorization", + "available_request_authorization", + "request_authorization", + "ready_for_train", + "requirements_to_train", + "languages_ready_for_train", + "languages_warnings", + "created_at", ] ref_name = None owner = serializers.PrimaryKeyRelatedField( - read_only=True, - default=serializers.CurrentUserDefault()) + read_only=True, default=serializers.CurrentUserDefault() + ) owner__nickname = serializers.SlugRelatedField( - source='owner', - slug_field='nickname', - read_only=True) - categories = RepositoryCategorySerializer( - many=True, - read_only=True) + source="owner", slug_field="nickname", read_only=True + ) + categories = RepositoryCategorySerializer(many=True, read_only=True) categories_list = serializers.SerializerMethodField() entities = serializers.SerializerMethodField() labels = RepositoryEntityLabelSerializer(many=True) @@ -118,17 +114,18 @@ def get_labels_list(self, obj): return list(obj.labels_list) def get_authorization(self, obj): - request = self.context.get('request') + request = self.context.get("request") if not request: return None # pragma: no cover return RepositoryAuthorizationSerializer( - obj.get_user_authorization(request.user)).data + obj.get_user_authorization(request.user) + ).data def get_examples__count(self, obj): return obj.examples().count() def get_available_request_authorization(self, obj): - request = self.context.get('request') + request = self.context.get("request") if not request or not request.user.is_authenticated: return False authorization = obj.get_user_authorization(request.user) @@ -138,22 +135,21 @@ def get_available_request_authorization(self, obj): return False try: RequestRepositoryAuthorization.objects.get( - user=request.user, - repository=obj) + user=request.user, repository=obj + ) return False except RequestRepositoryAuthorization.DoesNotExist: return True def get_request_authorization(self, obj): - request = self.context.get('request') + request = self.context.get("request") if not request or not request.user.is_authenticated: return None try: request_authorization = RequestRepositoryAuthorization.objects.get( - user=request.user, - repository=obj) - return RequestRepositoryAuthorizationSerializer( - request_authorization).data + user=request.user, repository=obj + ) + return RequestRepositoryAuthorizationSerializer(request_authorization).data except RequestRepositoryAuthorization.DoesNotExist: return None @@ -162,24 +158,23 @@ class RepositoryAuthorizationSerializer(serializers.ModelSerializer): class Meta: model = RepositoryAuthorization fields = [ - 'uuid', - 'user', - 'user__nickname', - 'repository', - 'role', - 'level', - 'can_read', - 'can_contribute', - 'can_write', - 'is_admin', - 'created_at', + "uuid", + "user", + "user__nickname", + "repository", + "role", + "level", + "can_read", + "can_contribute", + "can_write", + "is_admin", + "created_at", ] ref_name = None user__nickname = serializers.SlugRelatedField( - source='user', - slug_field='nickname', - read_only=True) + source="user", slug_field="nickname", read_only=True + ) class AnalyzeTextSerializer(serializers.Serializer): @@ -194,12 +189,10 @@ class EvaluateSerializer(serializers.Serializer): class RepositoryAuthorizationRoleSerializer(serializers.ModelSerializer): class Meta: model = RepositoryAuthorization - fields = [ - 'role', - ] + fields = ["role"] ref_name = None def validate(self, data): if self.instance.user == self.instance.repository.owner: - raise PermissionDenied(_('The owner role can\'t be changed.')) + raise PermissionDenied(_("The owner role can't be changed.")) return data diff --git a/bothub/api/v1/serializers/request.py b/bothub/api/v1/serializers/request.py index dad0c52e..775c649c 100644 --- a/bothub/api/v1/serializers/request.py +++ b/bothub/api/v1/serializers/request.py @@ -9,65 +9,55 @@ class NewRequestRepositoryAuthorizationSerializer(serializers.ModelSerializer): class Meta: model = RequestRepositoryAuthorization - fields = [ - 'user', - 'repository', - 'text', - ] + fields = ["user", "repository", "text"] ref_name = None repository = serializers.PrimaryKeyRelatedField( - queryset=Repository.objects, - style={'show': False}) + queryset=Repository.objects, style={"show": False} + ) user = serializers.HiddenField( - default=serializers.CurrentUserDefault(), - style={'show': False}) + default=serializers.CurrentUserDefault(), style={"show": False} + ) text = TextField( - label=_('Leave a message for repository administrators'), + label=_("Leave a message for repository administrators"), min_length=5, - max_length=RequestRepositoryAuthorization._meta.get_field( - 'text').max_length) + max_length=RequestRepositoryAuthorization._meta.get_field("text").max_length, + ) class RequestRepositoryAuthorizationSerializer(serializers.ModelSerializer): class Meta: model = RequestRepositoryAuthorization fields = [ - 'id', - 'user', - 'user__nickname', - 'repository', - 'text', - 'approved_by', - 'approved_by__nickname', - 'created_at', + "id", + "user", + "user__nickname", + "repository", + "text", + "approved_by", + "approved_by__nickname", + "created_at", ] ref_name = None user__nickname = serializers.SlugRelatedField( - source='user', - slug_field='nickname', - read_only=True) + source="user", slug_field="nickname", read_only=True + ) approved_by__nickname = serializers.SlugRelatedField( - source='approved_by', - slug_field='nickname', - read_only=True) + source="approved_by", slug_field="nickname", read_only=True + ) class ReviewAuthorizationRequestSerializer(serializers.ModelSerializer): class Meta: model = RequestRepositoryAuthorization - fields = [ - 'approved_by' - ] + fields = ["approved_by"] ref_name = None approved_by = serializers.PrimaryKeyRelatedField( - read_only=True, - style={'show': False}) + read_only=True, style={"show": False} + ) def update(self, instance, validated_data): - validated_data.update({ - 'approved_by': self.context['request'].user, - }) + validated_data.update({"approved_by": self.context["request"].user}) return super().update(instance, validated_data) diff --git a/bothub/api/v1/serializers/translate.py b/bothub/api/v1/serializers/translate.py index 673a3d00..f62365d9 100644 --- a/bothub/api/v1/serializers/translate.py +++ b/bothub/api/v1/serializers/translate.py @@ -18,21 +18,20 @@ class RepositoryTranslatedExampleEntitySeralizer(serializers.ModelSerializer): class Meta: model = RepositoryTranslatedExampleEntity fields = [ - 'id', - 'repository_translated_example', - 'start', - 'end', - 'entity', - 'created_at', - 'value', + "id", + "repository_translated_example", + "start", + "end", + "entity", + "created_at", + "value", ] repository_translated_example = serializers.PrimaryKeyRelatedField( queryset=RepositoryTranslatedExample.objects, - validators=[ - CanContributeInRepositoryTranslatedExampleValidator(), - ], - help_text='Example translation ID') + validators=[CanContributeInRepositoryTranslatedExampleValidator()], + help_text="Example translation ID", + ) entity = serializers.SerializerMethodField() value = serializers.SerializerMethodField() @@ -47,28 +46,25 @@ class RepositoryTranslatedExampleSerializer(serializers.ModelSerializer): class Meta: model = RepositoryTranslatedExample fields = [ - 'id', - 'original_example', - 'from_language', - 'language', - 'text', - 'has_valid_entities', - 'entities', - 'created_at', + "id", + "original_example", + "from_language", + "language", + "text", + "has_valid_entities", + "entities", + "created_at", ] ref_name = None original_example = serializers.PrimaryKeyRelatedField( queryset=RepositoryExample.objects, - validators=[ - CanContributeInRepositoryExampleValidator(), - ], - help_text=_('Example\'s ID')) + validators=[CanContributeInRepositoryExampleValidator()], + help_text=_("Example's ID"), + ) from_language = serializers.SerializerMethodField() has_valid_entities = serializers.SerializerMethodField() - entities = RepositoryTranslatedExampleEntitySeralizer( - many=True, - read_only=True) + entities = RepositoryTranslatedExampleEntitySeralizer(many=True, read_only=True) def get_from_language(self, obj): return obj.original_example.repository_update.language @@ -77,15 +73,10 @@ def get_has_valid_entities(self, obj): return obj.has_valid_entities -class NewRepositoryTranslatedExampleEntitySeralizer( - serializers.ModelSerializer): +class NewRepositoryTranslatedExampleEntitySeralizer(serializers.ModelSerializer): class Meta: model = RepositoryTranslatedExampleEntity - fields = [ - 'start', - 'end', - 'entity', - ] + fields = ["start", "end", "entity"] entity = EntityValueField() @@ -94,12 +85,12 @@ class NewRepositoryTranslatedExampleSerializer(serializers.ModelSerializer): class Meta: model = RepositoryTranslatedExample fields = [ - 'id', - 'original_example', - 'language', - 'text', - 'has_valid_entities', - 'entities', + "id", + "original_example", + "language", + "text", + "has_valid_entities", + "entities", ] ref_name = None @@ -110,27 +101,24 @@ def __init__(self, *args, **kwargs): original_example = serializers.PrimaryKeyRelatedField( queryset=RepositoryExample.objects, - validators=[ - CanContributeInRepositoryExampleValidator(), - ], - help_text=_('Example\'s ID')) - language = serializers.ChoiceField( - LANGUAGE_CHOICES, - label=_('Language')) + validators=[CanContributeInRepositoryExampleValidator()], + help_text=_("Example's ID"), + ) + language = serializers.ChoiceField(LANGUAGE_CHOICES, label=_("Language")) has_valid_entities = serializers.SerializerMethodField() entities = NewRepositoryTranslatedExampleEntitySeralizer( - many=True, - style={'text_field': 'text'}) + many=True, style={"text_field": "text"} + ) def get_has_valid_entities(self, obj): return obj.has_valid_entities def create(self, validated_data): - entities_data = validated_data.pop('entities') + entities_data = validated_data.pop("entities") translated = self.Meta.model.objects.create(**validated_data) for entity_data in entities_data: RepositoryTranslatedExampleEntity.objects.create( - repository_translated_example=translated, - **entity_data) + repository_translated_example=translated, **entity_data + ) return translated diff --git a/bothub/api/v1/serializers/update.py b/bothub/api/v1/serializers/update.py index 0cf66704..ab57472c 100644 --- a/bothub/api/v1/serializers/update.py +++ b/bothub/api/v1/serializers/update.py @@ -7,19 +7,18 @@ class RepositoryUpdateSerializer(serializers.ModelSerializer): class Meta: model = RepositoryUpdate fields = [ - 'id', - 'repository', - 'language', - 'created_at', - 'by', - 'by__nickname', - 'training_started_at', - 'trained_at', - 'failed_at', + "id", + "repository", + "language", + "created_at", + "by", + "by__nickname", + "training_started_at", + "trained_at", + "failed_at", ] ref_name = None by__nickname = serializers.SlugRelatedField( - source='by', - slug_field='nickname', - read_only=True) + source="by", slug_field="nickname", read_only=True + ) diff --git a/bothub/api/v1/serializers/user.py b/bothub/api/v1/serializers/user.py index b45da18b..a8ebf7cb 100644 --- a/bothub/api/v1/serializers/user.py +++ b/bothub/api/v1/serializers/user.py @@ -13,19 +13,10 @@ class RegisterUserSerializer(serializers.ModelSerializer): class Meta: model = User - fields = [ - 'email', - 'name', - 'nickname', - 'password', - ] + fields = ["email", "name", "nickname", "password"] ref_name = None - password = PasswordField( - write_only=True, - validators=[ - validate_password, - ]) + password = PasswordField(write_only=True, validators=[validate_password]) def validate_password(self, value): return make_password(value) @@ -34,63 +25,45 @@ def validate_password(self, value): class UserSerializer(serializers.ModelSerializer): class Meta: model = User - fields = [ - 'nickname', - 'name', - 'locale', - ] + fields = ["nickname", "name", "locale"] ref_name = None class ChangePasswordSerializer(serializers.Serializer): - current_password = PasswordField( - required=True) - password = PasswordField( - required=True, - validators=[ - validate_password, - ]) + current_password = PasswordField(required=True) + password = PasswordField(required=True, validators=[validate_password]) def validate_current_password(self, value): - request = self.context.get('request') + request = self.context.get("request") if not request.user.check_password(value): - raise ValidationError(_('Wrong password')) + raise ValidationError(_("Wrong password")) return value class RequestResetPasswordSerializer(serializers.Serializer): - email = serializers.EmailField( - label=_('Email'), - required=True) + email = serializers.EmailField(label=_("Email"), required=True) def validate_email(self, value): try: User.objects.get(email=value) return value except User.DoesNotExist: - raise ValidationError(_('No user registered with this email')) + raise ValidationError(_("No user registered with this email")) class ResetPasswordSerializer(serializers.Serializer): - token = serializers.CharField( - label=_('Token'), - style={'show': False}) + token = serializers.CharField(label=_("Token"), style={"show": False}) password = PasswordField( - label=_('New Password'), - required=True, - validators=[ - validate_password, - ]) + label=_("New Password"), required=True, validators=[validate_password] + ) def validate_token(self, value): - user = self.context.get('view').get_object() + user = self.context.get("view").get_object() if not user.check_password_reset_token(value): - raise ValidationError(_('Invalid token for this user')) + raise ValidationError(_("Invalid token for this user")) return value class LoginSerializer(AuthTokenSerializer): username = serializers.EmailField(label=_("Email")) - password = PasswordField( - label=_("Password") - ) + password = PasswordField(label=_("Password")) diff --git a/bothub/api/v1/tests/test_authorization.py b/bothub/api/v1/tests/test_authorization.py index 24ab35e3..564e219b 100644 --- a/bothub/api/v1/tests/test_authorization.py +++ b/bothub/api/v1/tests/test_authorization.py @@ -20,218 +20,166 @@ class AuthorizationTestCase(TestCase): def setUp(self): self.factory = RequestFactory() - self.owner, self.owner_token = create_user_and_token('owner') + self.owner, self.owner_token = create_user_and_token("owner") self.user, self.user_token = create_user_and_token() self.repository = Repository.objects.create( owner=self.owner, - name='Testing', - slug='test', - language=languages.LANGUAGE_EN) + name="Testing", + slug="test", + language=languages.LANGUAGE_EN, + ) self.private_repository = Repository.objects.create( owner=self.owner, - name='Testing Private', - slug='private', + name="Testing Private", + slug="private", language=languages.LANGUAGE_EN, - is_private=True) + is_private=True, + ) def request(self, repository, token): - authorization_header = { - 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), - } + authorization_header = {"HTTP_AUTHORIZATION": "Token {}".format(token.key)} request = self.factory.get( - '/v1/repository/{}/{}/'.format( - repository.owner.nickname, - repository.slug), - **authorization_header) - response = RepositoryViewSet.as_view( - {'get': 'authorization'})( - request, - owner__nickname=repository.owner.nickname, - slug=repository.slug) + "/v1/repository/{}/{}/".format(repository.owner.nickname, repository.slug), + **authorization_header + ) + response = RepositoryViewSet.as_view({"get": "authorization"})( + request, owner__nickname=repository.owner.nickname, slug=repository.slug + ) response.render() content_data = json.loads(response.content) - return (response, content_data,) + return (response, content_data) def test_owner_allowed_public(self): - response, content_data = self.request( - self.repository, - self.owner_token) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) - self.assertEqual( - content_data.get('user'), - self.owner.id) + response, content_data = self.request(self.repository, self.owner_token) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(content_data.get("user"), self.owner.id) def test_user_allowed_public(self): - response, content_data = self.request( - self.repository, - self.user_token) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) - self.assertEqual( - content_data.get('user'), - self.user.id) + response, content_data = self.request(self.repository, self.user_token) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(content_data.get("user"), self.user.id) def test_owner_allowed_private(self): - response, content_data = self.request( - self.private_repository, - self.owner_token) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) - self.assertEqual( - content_data.get('user'), - self.owner.id) + response, content_data = self.request(self.private_repository, self.owner_token) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(content_data.get("user"), self.owner.id) def test_user_forbidden_private(self): - response, content_data = self.request( - self.private_repository, - self.user_token) - self.assertEqual( - response.status_code, - status.HTTP_403_FORBIDDEN) + response, content_data = self.request(self.private_repository, self.user_token) + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) class ListAuthorizationTestCase(TestCase): def setUp(self): self.factory = RequestFactory() - self.owner, self.owner_token = create_user_and_token('owner') + self.owner, self.owner_token = create_user_and_token("owner") self.user, self.user_token = create_user_and_token() self.repository = Repository.objects.create( owner=self.owner, - name='Testing', - slug='test', - language=languages.LANGUAGE_EN) + name="Testing", + slug="test", + language=languages.LANGUAGE_EN, + ) self.user_auth = self.repository.get_user_authorization(self.user) self.user_auth.role = RepositoryAuthorization.ROLE_CONTRIBUTOR self.user_auth.save() def request(self, repository, token): - authorization_header = { - 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), - } + authorization_header = {"HTTP_AUTHORIZATION": "Token {}".format(token.key)} request = self.factory.get( - '/v1/list-authorizations/', - { - 'repository': repository.uuid, - }, - **authorization_header) - response = RepositoryAuthorizationViewSet.as_view( - {'get': 'list'})(request) + "/v1/list-authorizations/", + {"repository": repository.uuid}, + **authorization_header + ) + response = RepositoryAuthorizationViewSet.as_view({"get": "list"})(request) response.render() content_data = json.loads(response.content) - return (response, content_data,) + return (response, content_data) def test_okay(self): - response, content_data = self.request( - self.repository, - self.owner_token) + response, content_data = self.request(self.repository, self.owner_token) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) + self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual( - content_data.get('count'), - 1) + self.assertEqual(content_data.get("count"), 1) - self.assertEqual( - content_data.get('results')[0].get('user'), - self.user.id) + self.assertEqual(content_data.get("results")[0].get("user"), self.user.id) def test_user_forbidden(self): - response, content_data = self.request( - self.repository, - self.user_token) + response, content_data = self.request(self.repository, self.user_token) - self.assertEqual( - response.status_code, - status.HTTP_403_FORBIDDEN) + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) class UpdateAuthorizationRoleTestCase(TestCase): def setUp(self): self.factory = RequestFactory() - self.owner, self.owner_token = create_user_and_token('owner') + self.owner, self.owner_token = create_user_and_token("owner") self.user, self.user_token = create_user_and_token() self.repository = Repository.objects.create( owner=self.owner, - name='Testing', - slug='test', - language=languages.LANGUAGE_EN) + name="Testing", + slug="test", + language=languages.LANGUAGE_EN, + ) def request(self, repository, token, user, data): - authorization_header = { - 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), - } + authorization_header = {"HTTP_AUTHORIZATION": "Token {}".format(token.key)} request = self.factory.patch( - '/v1/authorization-role/{}/{}/'.format( - repository.uuid, user.nickname), + "/v1/authorization-role/{}/{}/".format(repository.uuid, user.nickname), self.factory._encode_data(data, MULTIPART_CONTENT), MULTIPART_CONTENT, - **authorization_header) - view = RepositoryAuthorizationRoleViewSet.as_view( - {'patch': 'update'}) + **authorization_header + ) + view = RepositoryAuthorizationRoleViewSet.as_view({"patch": "update"}) response = view( - request, - repository__uuid=repository.uuid, - user__nickname=user.nickname) + request, repository__uuid=repository.uuid, user__nickname=user.nickname + ) response.render() content_data = json.loads(response.content) - return (response, content_data,) + return (response, content_data) def test_okay(self): response, content_data = self.request( self.repository, self.owner_token, self.user, - { - 'role': RepositoryAuthorization.ROLE_CONTRIBUTOR, - }) + {"role": RepositoryAuthorization.ROLE_CONTRIBUTOR}, + ) + self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual( - response.status_code, - status.HTTP_200_OK) - self.assertEqual( - content_data.get('role'), - RepositoryAuthorization.ROLE_CONTRIBUTOR) + content_data.get("role"), RepositoryAuthorization.ROLE_CONTRIBUTOR + ) user_authorization = self.repository.get_user_authorization(self.user) self.assertEqual( - user_authorization.role, - RepositoryAuthorization.ROLE_CONTRIBUTOR) + user_authorization.role, RepositoryAuthorization.ROLE_CONTRIBUTOR + ) def test_forbidden(self): response, content_data = self.request( self.repository, self.user_token, self.user, - { - 'role': RepositoryAuthorization.ROLE_CONTRIBUTOR, - }) + {"role": RepositoryAuthorization.ROLE_CONTRIBUTOR}, + ) - self.assertEqual( - response.status_code, - status.HTTP_403_FORBIDDEN) + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) def test_owner_can_t_set_your_role(self): response, content_data = self.request( self.repository, self.owner_token, self.owner, - { - 'role': RepositoryAuthorization.ROLE_CONTRIBUTOR, - }) + {"role": RepositoryAuthorization.ROLE_CONTRIBUTOR}, + ) - self.assertEqual( - response.status_code, - status.HTTP_403_FORBIDDEN) + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) diff --git a/bothub/api/v1/tests/test_categories.py b/bothub/api/v1/tests/test_categories.py index 3de426df..4c81aa21 100644 --- a/bothub/api/v1/tests/test_categories.py +++ b/bothub/api/v1/tests/test_categories.py @@ -12,33 +12,24 @@ class CategoriesTestCase(TestCase): def setUp(self): self.factory = RequestFactory() - self.category = RepositoryCategory.objects.create(name='Category 1') + self.category = RepositoryCategory.objects.create(name="Category 1") self.business_category = RepositoryCategory.objects.create( - name='Business', - icon='business') + name="Business", icon="business" + ) def request(self): - request = self.factory.get('/v1/categories/') - response = Categories.as_view( - {'get': 'list'})(request) + request = self.factory.get("/v1/categories/") + response = Categories.as_view({"get": "list"})(request) response.render() content_data = json.loads(response.content) - return (response, content_data,) + return (response, content_data) def test_default_category_icon(self): response, content_data = self.request() - self.assertEqual( - content_data[0].get('id'), - self.category.id) - self.assertEqual( - content_data[0].get('icon'), - 'botinho') + self.assertEqual(content_data[0].get("id"), self.category.id) + self.assertEqual(content_data[0].get("icon"), "botinho") def test_custom_category_icon(self): response, content_data = self.request() - self.assertEqual( - content_data[1].get('id'), - self.business_category.id) - self.assertEqual( - content_data[1].get('icon'), - self.business_category.icon) + self.assertEqual(content_data[1].get("id"), self.business_category.id) + self.assertEqual(content_data[1].get("icon"), self.business_category.icon) diff --git a/bothub/api/v1/tests/test_example.py b/bothub/api/v1/tests/test_example.py index 0a9fd157..3dd0db46 100644 --- a/bothub/api/v1/tests/test_example.py +++ b/bothub/api/v1/tests/test_example.py @@ -22,211 +22,164 @@ class NewRepositoryExampleTestCase(TestCase): def setUp(self): self.factory = RequestFactory() - self.owner, self.owner_token = create_user_and_token('owner') + self.owner, self.owner_token = create_user_and_token("owner") self.user, self.user_token = create_user_and_token() self.repository = Repository.objects.create( owner=self.owner, - name='Testing', - slug='test', - language=languages.LANGUAGE_EN) + name="Testing", + slug="test", + language=languages.LANGUAGE_EN, + ) def request(self, token, data): - authorization_header = { - 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), - } + authorization_header = {"HTTP_AUTHORIZATION": "Token {}".format(token.key)} request = self.factory.post( - '/v1/example/new/', + "/v1/example/new/", json.dumps(data), - content_type='application/json', - **authorization_header) - response = NewRepositoryExampleViewSet.as_view( - {'post': 'create'})(request) + content_type="application/json", + **authorization_header + ) + response = NewRepositoryExampleViewSet.as_view({"post": "create"})(request) response.render() content_data = json.loads(response.content) - return (response, content_data,) + return (response, content_data) def test_okay(self): - text = 'hi' - intent = 'greet' + text = "hi" + intent = "greet" response, content_data = self.request( self.owner_token, { - 'repository': str(self.repository.uuid), - 'text': text, - 'intent': intent, - 'entities': [], - }) - self.assertEqual( - response.status_code, - status.HTTP_201_CREATED) - self.assertEqual( - content_data.get('text'), - text) - self.assertEqual( - content_data.get('intent'), - intent) + "repository": str(self.repository.uuid), + "text": text, + "intent": intent, + "entities": [], + }, + ) + self.assertEqual(response.status_code, status.HTTP_201_CREATED) + self.assertEqual(content_data.get("text"), text) + self.assertEqual(content_data.get("intent"), intent) def test_okay_with_language(self): - text = 'hi' - intent = 'greet' + text = "hi" + intent = "greet" language = languages.LANGUAGE_PT response, content_data = self.request( self.owner_token, { - 'repository': str(self.repository.uuid), - 'text': text, - 'language': language, - 'intent': intent, - 'entities': [], - }) - self.assertEqual( - response.status_code, - status.HTTP_201_CREATED) - self.assertEqual( - content_data.get('text'), - text) - self.assertEqual( - content_data.get('intent'), - intent) - repository_update_pk = content_data.get('repository_update') - repository_update = RepositoryUpdate.objects.get( - pk=repository_update_pk) + "repository": str(self.repository.uuid), + "text": text, + "language": language, + "intent": intent, + "entities": [], + }, + ) + self.assertEqual(response.status_code, status.HTTP_201_CREATED) + self.assertEqual(content_data.get("text"), text) + self.assertEqual(content_data.get("intent"), intent) + repository_update_pk = content_data.get("repository_update") + repository_update = RepositoryUpdate.objects.get(pk=repository_update_pk) self.assertEqual(repository_update.language, language) def test_forbidden(self): response, content_data = self.request( self.user_token, { - 'repository': str(self.repository.uuid), - 'text': 'hi', - 'intent': 'greet', - 'entities': [], - }) - self.assertEqual( - response.status_code, - status.HTTP_403_FORBIDDEN) + "repository": str(self.repository.uuid), + "text": "hi", + "intent": "greet", + "entities": [], + }, + ) + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) def test_repository_uuid_required(self): response, content_data = self.request( - self.owner_token, - { - 'text': 'hi', - 'intent': 'greet', - 'entities': [], - }) - self.assertEqual( - response.status_code, - status.HTTP_400_BAD_REQUEST) + self.owner_token, {"text": "hi", "intent": "greet", "entities": []} + ) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) def test_repository_does_not_exists(self): response, content_data = self.request( self.owner_token, { - 'repository': str(uuid.uuid4()), - 'text': 'hi', - 'intent': 'greet', - 'entities': [], - }) - self.assertEqual( - response.status_code, - status.HTTP_400_BAD_REQUEST) - self.assertIn( - 'repository', - content_data.keys()) + "repository": str(uuid.uuid4()), + "text": "hi", + "intent": "greet", + "entities": [], + }, + ) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + self.assertIn("repository", content_data.keys()) def test_invalid_repository_uuid(self): response, content_data = self.request( self.owner_token, - { - 'repository': 'invalid', - 'text': 'hi', - 'intent': 'greet', - 'entities': [], - }) - self.assertEqual( - response.status_code, - status.HTTP_400_BAD_REQUEST) + {"repository": "invalid", "text": "hi", "intent": "greet", "entities": []}, + ) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) def test_with_entities(self): response, content_data = self.request( self.owner_token, { - 'repository': str(self.repository.uuid), - 'text': 'my name is user', - 'intent': 'greet', - 'entities': [ - { - 'start': 11, - 'end': 18, - 'entity': 'name', - }, - ], - }) - self.assertEqual( - response.status_code, - status.HTTP_201_CREATED) - self.assertEqual( - len(content_data.get('entities')), - 1) + "repository": str(self.repository.uuid), + "text": "my name is user", + "intent": "greet", + "entities": [{"start": 11, "end": 18, "entity": "name"}], + }, + ) + self.assertEqual(response.status_code, status.HTTP_201_CREATED) + self.assertEqual(len(content_data.get("entities")), 1) def test_exists_example(self): - text = 'hi' - intent = 'greet' + text = "hi" + intent = "greet" response_created, content_data_created = self.request( self.owner_token, { - 'repository': str(self.repository.uuid), - 'text': text, - 'intent': intent, - 'entities': [], - }) + "repository": str(self.repository.uuid), + "text": text, + "intent": intent, + "entities": [], + }, + ) - self.assertEqual( - response_created.status_code, - status.HTTP_201_CREATED) + self.assertEqual(response_created.status_code, status.HTTP_201_CREATED) response, content_data = self.request( self.owner_token, { - 'repository': str(self.repository.uuid), - 'text': text, - 'intent': intent, - 'entities': [], - }) + "repository": str(self.repository.uuid), + "text": text, + "intent": intent, + "entities": [], + }, + ) self.assertEqual( - content_data.get('non_field_errors')[0], - 'Intention and Sentence already exists' + content_data.get("non_field_errors")[0], + "Intention and Sentence already exists", ) - self.assertEqual( - response.status_code, - status.HTTP_400_BAD_REQUEST) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) def test_with_entities_with_label(self): response, content_data = self.request( self.owner_token, { - 'repository': str(self.repository.uuid), - 'text': 'my name is user', - 'intent': 'greet', - 'entities': [ - { - 'start': 11, - 'end': 18, - 'entity': 'name', - 'label': 'subject', - }, + "repository": str(self.repository.uuid), + "text": "my name is user", + "intent": "greet", + "entities": [ + {"start": 11, "end": 18, "entity": "name", "label": "subject"} ], - }) - self.assertEqual( - response.status_code, - status.HTTP_201_CREATED) - self.assertEqual( - len(content_data.get('entities')), - 1) - id = content_data.get('id') + }, + ) + self.assertEqual(response.status_code, status.HTTP_201_CREATED) + self.assertEqual(len(content_data.get("entities")), 1) + id = content_data.get("id") repository_example = RepositoryExample.objects.get(id=id) example_entity = repository_example.entities.all()[0] self.assertIsNotNone(example_entity.entity.label) @@ -235,444 +188,329 @@ def test_with_entities_with_invalid_label(self): response, content_data = self.request( self.owner_token, { - 'repository': str(self.repository.uuid), - 'text': 'my name is user', - 'intent': 'greet', - 'entities': [ - { - 'start': 11, - 'end': 18, - 'entity': 'name', - 'label': 'other', - }, + "repository": str(self.repository.uuid), + "text": "my name is user", + "intent": "greet", + "entities": [ + {"start": 11, "end": 18, "entity": "name", "label": "other"} ], - }) - self.assertEqual( - response.status_code, - status.HTTP_400_BAD_REQUEST) - self.assertIn( - 'entities', - content_data.keys()) - entities_errors = content_data.get('entities') - self.assertIn( - 'label', - entities_errors[0]) + }, + ) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + self.assertIn("entities", content_data.keys()) + entities_errors = content_data.get("entities") + self.assertIn("label", entities_errors[0]) def test_with_entities_with_equal_label(self): response, content_data = self.request( self.owner_token, { - 'repository': str(self.repository.uuid), - 'text': 'my name is user', - 'intent': 'greet', - 'entities': [ - { - 'start': 11, - 'end': 18, - 'entity': 'name', - 'label': 'name', - }, + "repository": str(self.repository.uuid), + "text": "my name is user", + "intent": "greet", + "entities": [ + {"start": 11, "end": 18, "entity": "name", "label": "name"} ], - }) - self.assertEqual( - response.status_code, - status.HTTP_400_BAD_REQUEST) - self.assertIn( - 'entities', - content_data.keys()) - entities_errors = content_data.get('entities') - self.assertIn( - 'label', - entities_errors[0]) + }, + ) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + self.assertIn("entities", content_data.keys()) + entities_errors = content_data.get("entities") + self.assertIn("label", entities_errors[0]) def test_intent_or_entity_required(self): response, content_data = self.request( self.owner_token, { - 'repository': str(self.repository.uuid), - 'text': 'hi', - 'intent': '', - 'entities': [], - }) - self.assertEqual( - response.status_code, - status.HTTP_400_BAD_REQUEST) + "repository": str(self.repository.uuid), + "text": "hi", + "intent": "", + "entities": [], + }, + ) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) def test_entity_with_special_char(self): response, content_data = self.request( self.owner_token, { - 'repository': str(self.repository.uuid), - 'text': 'my name is user', - 'intent': '', - 'entities': [ - { - 'start': 11, - 'end': 18, - 'entity': 'nam&', - }, - ], - }) - self.assertEqual( - response.status_code, - status.HTTP_400_BAD_REQUEST) - self.assertEqual( - len(content_data.get('entities')), - 1) + "repository": str(self.repository.uuid), + "text": "my name is user", + "intent": "", + "entities": [{"start": 11, "end": 18, "entity": "nam&"}], + }, + ) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + self.assertEqual(len(content_data.get("entities")), 1) def test_intent_with_special_char(self): response, content_data = self.request( self.owner_token, { - 'repository': str(self.repository.uuid), - 'text': 'my name is user', - 'intent': 'nam$s', - 'entities': [], - }) - self.assertEqual( - response.status_code, - status.HTTP_400_BAD_REQUEST) - self.assertEqual( - len(content_data.get('intent')), - 1) + "repository": str(self.repository.uuid), + "text": "my name is user", + "intent": "nam$s", + "entities": [], + }, + ) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + self.assertEqual(len(content_data.get("intent")), 1) class RepositoryExampleRetrieveTestCase(TestCase): def setUp(self): self.factory = RequestFactory() - self.owner, self.owner_token = create_user_and_token('owner') + self.owner, self.owner_token = create_user_and_token("owner") self.user, self.user_token = create_user_and_token() self.repository = Repository.objects.create( owner=self.owner, - name='Testing', - slug='test', - language=languages.LANGUAGE_EN) + name="Testing", + slug="test", + language=languages.LANGUAGE_EN, + ) self.example = RepositoryExample.objects.create( - repository_update=self.repository.current_update(), - text='my name is user') + repository_update=self.repository.current_update(), text="my name is user" + ) self.example_entity = RepositoryExampleEntity.objects.create( - repository_example=self.example, - start=11, - end=18, - entity='name') + repository_example=self.example, start=11, end=18, entity="name" + ) self.private_repository = Repository.objects.create( owner=self.owner, - name='Testing Private', - slug='private', + name="Testing Private", + slug="private", language=languages.LANGUAGE_EN, - is_private=True) + is_private=True, + ) self.private_example = RepositoryExample.objects.create( - repository_update=self.private_repository.current_update(), - text='hi') + repository_update=self.private_repository.current_update(), text="hi" + ) def request(self, example, token): - authorization_header = { - 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), - } + authorization_header = {"HTTP_AUTHORIZATION": "Token {}".format(token.key)} request = self.factory.get( - '/v1/example/{}/'.format(example.id), - **authorization_header) - response = RepositoryExampleViewSet.as_view( - {'get': 'retrieve'})(request, pk=example.id) + "/v1/example/{}/".format(example.id), **authorization_header + ) + response = RepositoryExampleViewSet.as_view({"get": "retrieve"})( + request, pk=example.id + ) response.render() content_data = json.loads(response.content) - return (response, content_data,) + return (response, content_data) def test_okay(self): - response, content_data = self.request( - self.example, - self.owner_token) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) - self.assertEqual( - content_data.get('id'), - self.example.id) + response, content_data = self.request(self.example, self.owner_token) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(content_data.get("id"), self.example.id) def test_forbidden(self): - response, content_data = self.request( - self.private_example, - self.user_token) - self.assertEqual( - response.status_code, - status.HTTP_403_FORBIDDEN) + response, content_data = self.request(self.private_example, self.user_token) + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) def test_public(self): - response, content_data = self.request( - self.example, - self.user_token) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) - self.assertEqual( - content_data.get('id'), - self.example.id) + response, content_data = self.request(self.example, self.user_token) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(content_data.get("id"), self.example.id) def test_list_entities(self): - response, content_data = self.request( - self.example, - self.owner_token) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) - self.assertEqual( - len(content_data.get('entities')), - 1) + response, content_data = self.request(self.example, self.owner_token) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(len(content_data.get("entities")), 1) def test_entity_has_label(self): - response, content_data = self.request( - self.example, - self.owner_token) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) - entity = content_data.get('entities')[0] - self.assertIn( - 'label', - entity.keys()) + response, content_data = self.request(self.example, self.owner_token) + self.assertEqual(response.status_code, status.HTTP_200_OK) + entity = content_data.get("entities")[0] + self.assertIn("label", entity.keys()) def test_entity_has_valid_label(self): - label = 'subject' - self.example_entity.entity.set_label('subject') - self.example_entity.entity.save(update_fields=['label']) - response, content_data = self.request( - self.example, - self.owner_token) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) - entity = content_data.get('entities')[0] - self.assertIn( - 'label', - entity.keys()) - self.assertEqual( - entity.get('label'), - label) + label = "subject" + self.example_entity.entity.set_label("subject") + self.example_entity.entity.save(update_fields=["label"]) + response, content_data = self.request(self.example, self.owner_token) + self.assertEqual(response.status_code, status.HTTP_200_OK) + entity = content_data.get("entities")[0] + self.assertIn("label", entity.keys()) + self.assertEqual(entity.get("label"), label) class RepositoryExampleDestroyTestCase(TestCase): def setUp(self): self.factory = RequestFactory() - self.owner, self.owner_token = create_user_and_token('owner') + self.owner, self.owner_token = create_user_and_token("owner") self.user, self.user_token = create_user_and_token() self.repository = Repository.objects.create( owner=self.owner, - name='Testing', - slug='test', - language=languages.LANGUAGE_EN) + name="Testing", + slug="test", + language=languages.LANGUAGE_EN, + ) self.example = RepositoryExample.objects.create( - repository_update=self.repository.current_update(), - text='hi') + repository_update=self.repository.current_update(), text="hi" + ) self.private_repository = Repository.objects.create( owner=self.owner, - name='Testing Private', - slug='private', + name="Testing Private", + slug="private", language=languages.LANGUAGE_EN, - is_private=True) + is_private=True, + ) self.private_example = RepositoryExample.objects.create( - repository_update=self.private_repository.current_update(), - text='hi') + repository_update=self.private_repository.current_update(), text="hi" + ) def request(self, example, token): - authorization_header = { - 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), - } + authorization_header = {"HTTP_AUTHORIZATION": "Token {}".format(token.key)} request = self.factory.delete( - '/v1/example/{}/'.format(example.id), - **authorization_header) - response = RepositoryExampleViewSet.as_view( - {'delete': 'destroy'})(request, pk=example.id) + "/v1/example/{}/".format(example.id), **authorization_header + ) + response = RepositoryExampleViewSet.as_view({"delete": "destroy"})( + request, pk=example.id + ) return response def test_okay(self): - response = self.request( - self.example, - self.owner_token) - self.assertEqual( - response.status_code, - status.HTTP_204_NO_CONTENT) + response = self.request(self.example, self.owner_token) + self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) def test_private_okay(self): - response = self.request( - self.private_example, - self.owner_token) - self.assertEqual( - response.status_code, - status.HTTP_204_NO_CONTENT) + response = self.request(self.private_example, self.owner_token) + self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) def test_forbidden(self): - response = self.request( - self.example, - self.user_token) - self.assertEqual( - response.status_code, - status.HTTP_403_FORBIDDEN) + response = self.request(self.example, self.user_token) + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) def test_private_forbidden(self): - response = self.request( - self.private_example, - self.user_token) - self.assertEqual( - response.status_code, - status.HTTP_403_FORBIDDEN) + response = self.request(self.private_example, self.user_token) + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) def test_already_deleted(self): self.example.delete() - response = self.request( - self.example, - self.owner_token) - self.assertEqual( - response.status_code, - status.HTTP_500_INTERNAL_SERVER_ERROR) + response = self.request(self.example, self.owner_token) + self.assertEqual(response.status_code, status.HTTP_500_INTERNAL_SERVER_ERROR) class RepositoryExampleUpdateTestCase(TestCase): def setUp(self): self.factory = RequestFactory() - self.owner, self.owner_token = create_user_and_token('owner') + self.owner, self.owner_token = create_user_and_token("owner") self.user, self.user_token = create_user_and_token() self.repository = Repository.objects.create( owner=self.owner, - name='Testing', - slug='test', - language=languages.LANGUAGE_EN) + name="Testing", + slug="test", + language=languages.LANGUAGE_EN, + ) self.example = RepositoryExample.objects.create( - repository_update=self.repository.current_update(), - text='hi') + repository_update=self.repository.current_update(), text="hi" + ) self.private_repository = Repository.objects.create( owner=self.owner, - name='Testing Private', - slug='private', + name="Testing Private", + slug="private", language=languages.LANGUAGE_EN, - is_private=True) + is_private=True, + ) self.private_example = RepositoryExample.objects.create( - repository_update=self.private_repository.current_update(), - text='hi') + repository_update=self.private_repository.current_update(), text="hi" + ) def request(self, example, token, data): - authorization_header = { - 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), - } + authorization_header = {"HTTP_AUTHORIZATION": "Token {}".format(token.key)} request = self.factory.patch( - '/v1/example/{}/'.format(example.id), + "/v1/example/{}/".format(example.id), json.dumps(data), - content_type='application/json', - **authorization_header) - response = RepositoryExampleViewSet.as_view( - {'patch': 'update'})(request, pk=example.id) + content_type="application/json", + **authorization_header + ) + response = RepositoryExampleViewSet.as_view({"patch": "update"})( + request, pk=example.id + ) response.render() content_data = json.loads(response.content) - return (response, content_data,) + return (response, content_data) def test_okay(self): - text = 'teste' - intent = 'teste1234' + text = "teste" + intent = "teste1234" response, content_data = self.request( - self.example, - self.owner_token, - {"text": text, "intent": intent} + self.example, self.owner_token, {"text": text, "intent": intent} ) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) - self.assertEqual( - content_data.get('text'), - text) - self.assertEqual( - content_data.get('intent'), - intent) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(content_data.get("text"), text) + self.assertEqual(content_data.get("intent"), intent) def test_private_forbidden(self): response, content_data = self.request( self.private_example, self.user_token, - {"text": 'teste', "intent": 'teste1234'}) + {"text": "teste", "intent": "teste1234"}, + ) - self.assertEqual( - response.status_code, - status.HTTP_403_FORBIDDEN) + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) class RepositoryEntitiesTestCase(TestCase): def setUp(self): self.factory = RequestFactory() - self.owner, self.owner_token = create_user_and_token('owner') + self.owner, self.owner_token = create_user_and_token("owner") self.user, self.user_token = create_user_and_token() - self.entity_value = 'user' + self.entity_value = "user" self.repository = Repository.objects.create( owner=self.owner, - name='Testing', - slug='test', - language=languages.LANGUAGE_EN) + name="Testing", + slug="test", + language=languages.LANGUAGE_EN, + ) self.example = RepositoryExample.objects.create( - repository_update=self.repository.current_update(), - text='my name is user') + repository_update=self.repository.current_update(), text="my name is user" + ) self.example_entity = RepositoryExampleEntity.objects.create( - repository_example=self.example, - start=11, - end=18, - entity=self.entity_value) - self.example_entity.entity.set_label('name') + repository_example=self.example, start=11, end=18, entity=self.entity_value + ) + self.example_entity.entity.set_label("name") self.example_entity.entity.save() def request(self, data, token): - authorization_header = { - 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), - } - request = self.factory.get( - '/v1/entities/', - data=data, - **authorization_header) - response = RepositoryEntitiesViewSet.as_view( - {'get': 'list'})(request) + authorization_header = {"HTTP_AUTHORIZATION": "Token {}".format(token.key)} + request = self.factory.get("/v1/entities/", data=data, **authorization_header) + response = RepositoryEntitiesViewSet.as_view({"get": "list"})(request) response.render() content_data = json.loads(response.content) - return (response, content_data,) + return (response, content_data) def test_okay(self): response, content_data = self.request( - { - 'repository_uuid': self.repository.uuid, - }, - self.owner_token) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) - self.assertEqual(content_data.get('count'), 1) + {"repository_uuid": self.repository.uuid}, self.owner_token + ) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(content_data.get("count"), 1) response, content_data = self.request( - { - 'repository_uuid': self.repository.uuid, - 'value': self.entity_value, - }, - self.owner_token) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) - self.assertEqual(content_data.get('count'), 1) + {"repository_uuid": self.repository.uuid, "value": self.entity_value}, + self.owner_token, + ) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(content_data.get("count"), 1) response, content_data = self.request( - { - 'repository_uuid': self.repository.uuid, - 'value': 'other', - }, - self.owner_token) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) - self.assertEqual(content_data.get('count'), 0) + {"repository_uuid": self.repository.uuid, "value": "other"}, + self.owner_token, + ) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(content_data.get("count"), 0) diff --git a/bothub/api/v1/tests/test_examples.py b/bothub/api/v1/tests/test_examples.py index 69ea60d3..a0ddd89f 100644 --- a/bothub/api/v1/tests/test_examples.py +++ b/bothub/api/v1/tests/test_examples.py @@ -19,254 +19,188 @@ class ExamplesTestCase(TestCase): def setUp(self): self.factory = RequestFactory() - self.owner, self.owner_token = create_user_and_token('owner') + self.owner, self.owner_token = create_user_and_token("owner") self.repository = Repository.objects.create( owner=self.owner, - name='Testing', - slug='test', - language=languages.LANGUAGE_EN) + name="Testing", + slug="test", + language=languages.LANGUAGE_EN, + ) self.example = RepositoryExample.objects.create( - repository_update=self.repository.current_update(), - text='hi') + repository_update=self.repository.current_update(), text="hi" + ) self.translated = RepositoryTranslatedExample.objects.create( - original_example=self.example, - text='oi', - language=languages.LANGUAGE_PT) + original_example=self.example, text="oi", language=languages.LANGUAGE_PT + ) self.deleted = RepositoryExample.objects.create( - repository_update=self.repository.current_update(), - text='hey') + repository_update=self.repository.current_update(), text="hey" + ) self.deleted.delete() self.private_repository = Repository.objects.create( owner=self.owner, - name='Private', - slug='private', + name="Private", + slug="private", language=languages.LANGUAGE_EN, - is_private=True) + is_private=True, + ) def request(self, data, token): - authorization_header = { - 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), - } - request = self.factory.get( - '/v1/examples/', - data, - **authorization_header) - response = RepositoryExamplesViewSet.as_view( - {'get': 'list'})(request) + authorization_header = {"HTTP_AUTHORIZATION": "Token {}".format(token.key)} + request = self.factory.get("/v1/examples/", data, **authorization_header) + response = RepositoryExamplesViewSet.as_view({"get": "list"})(request) response.render() content_data = json.loads(response.content) - return (response, content_data,) + return (response, content_data) def test_okay(self): response, content_data = self.request( - { - 'repository_uuid': self.repository.uuid, - }, - self.owner_token) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) + {"repository_uuid": self.repository.uuid}, self.owner_token + ) + self.assertEqual(response.status_code, status.HTTP_200_OK) def test_repository_uuid_required(self): - response, content_data = self.request( - {}, - self.owner_token) - self.assertEqual( - response.status_code, - status.HTTP_400_BAD_REQUEST) - self.assertEqual( - len(content_data.get('repository_uuid')), - 1) + response, content_data = self.request({}, self.owner_token) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + self.assertEqual(len(content_data.get("repository_uuid")), 1) def test_repository_does_not_exist(self): response, content_data = self.request( - { - 'repository_uuid': uuid.uuid4(), - }, - self.owner_token) - self.assertEqual( - response.status_code, - status.HTTP_404_NOT_FOUND) + {"repository_uuid": uuid.uuid4()}, self.owner_token + ) + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) def test_invalid_repository_uuid(self): response, content_data = self.request( - { - 'repository_uuid': 'invalid', - }, - self.owner_token) - self.assertEqual( - response.status_code, - status.HTTP_404_NOT_FOUND) + {"repository_uuid": "invalid"}, self.owner_token + ) + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) def test_language_filter(self): response_1, content_data_1 = self.request( { - 'repository_uuid': self.repository.uuid, - 'language': languages.LANGUAGE_EN, + "repository_uuid": self.repository.uuid, + "language": languages.LANGUAGE_EN, }, - self.owner_token) - self.assertEqual( - response_1.status_code, - status.HTTP_200_OK) - self.assertGreaterEqual( - content_data_1.get('count'), - 1) + self.owner_token, + ) + self.assertEqual(response_1.status_code, status.HTTP_200_OK) + self.assertGreaterEqual(content_data_1.get("count"), 1) response_2, content_data_2 = self.request( { - 'repository_uuid': self.repository.uuid, - 'language': languages.LANGUAGE_NL, + "repository_uuid": self.repository.uuid, + "language": languages.LANGUAGE_NL, }, - self.owner_token) - self.assertEqual( - response_2.status_code, - status.HTTP_200_OK) - self.assertEqual( - content_data_2.get('count'), - 0) + self.owner_token, + ) + self.assertEqual(response_2.status_code, status.HTTP_200_OK) + self.assertEqual(content_data_2.get("count"), 0) def test_has_translation_filter(self): response_1, content_data_1 = self.request( - { - 'repository_uuid': self.repository.uuid, - 'has_translation': True, - }, - self.owner_token) - self.assertEqual( - response_1.status_code, - status.HTTP_200_OK) - self.assertGreaterEqual( - content_data_1.get('count'), - 1) + {"repository_uuid": self.repository.uuid, "has_translation": True}, + self.owner_token, + ) + self.assertEqual(response_1.status_code, status.HTTP_200_OK) + self.assertGreaterEqual(content_data_1.get("count"), 1) response_2, content_data_2 = self.request( - { - 'repository_uuid': self.repository.uuid, - 'has_translation': False, - }, - self.owner_token) - self.assertEqual( - response_2.status_code, - status.HTTP_200_OK) - self.assertEqual( - content_data_2.get('count'), - 0) + {"repository_uuid": self.repository.uuid, "has_translation": False}, + self.owner_token, + ) + self.assertEqual(response_2.status_code, status.HTTP_200_OK) + self.assertEqual(content_data_2.get("count"), 0) def test_forbidden(self): user, user_token = create_user_and_token() response, content_data = self.request( - { - 'repository_uuid': self.private_repository.uuid, - }, - user_token) - self.assertEqual( - response.status_code, - status.HTTP_403_FORBIDDEN) + {"repository_uuid": self.private_repository.uuid}, user_token + ) + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) def test_dont_list_deleted(self): response, content_data = self.request( - { - 'repository_uuid': self.repository.uuid, - }, - self.owner_token) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) - for repository in content_data.get('results'): - self.failIf(self.deleted.id == repository.get('id')) + {"repository_uuid": self.repository.uuid}, self.owner_token + ) + self.assertEqual(response.status_code, status.HTTP_200_OK) + for repository in content_data.get("results"): + self.failIf(self.deleted.id == repository.get("id")) def test_order_by_translation(self): RepositoryExample.objects.create( - repository_update=self.repository.current_update(), - text='hello') + repository_update=self.repository.current_update(), text="hello" + ) example = RepositoryExample.objects.create( - repository_update=self.repository.current_update(), - text='how are you?') + repository_update=self.repository.current_update(), text="how are you?" + ) RepositoryTranslatedExample.objects.create( original_example=example, - text='com vai você?', - language=languages.LANGUAGE_PT) + text="com vai você?", + language=languages.LANGUAGE_PT, + ) RepositoryExample.objects.create( - repository_update=self.repository.current_update(), - text='hey') + repository_update=self.repository.current_update(), text="hey" + ) response, content_data = self.request( { - 'repository_uuid': self.repository.uuid, - 'order_by_translation': languages.LANGUAGE_PT, + "repository_uuid": self.repository.uuid, + "order_by_translation": languages.LANGUAGE_PT, }, - self.owner_token) - results = content_data.get('results') - self.assertGreaterEqual( - 0, - len(results[0].get('translations'))) - self.assertGreaterEqual( - 0, - len(results[1].get('translations'))) - self.assertGreaterEqual( - 1, - len(results[2].get('translations'))) - self.assertGreaterEqual( - 1, - len(results[3].get('translations'))) + self.owner_token, + ) + results = content_data.get("results") + self.assertGreaterEqual(0, len(results[0].get("translations"))) + self.assertGreaterEqual(0, len(results[1].get("translations"))) + self.assertGreaterEqual(1, len(results[2].get("translations"))) + self.assertGreaterEqual(1, len(results[3].get("translations"))) def test_order_by_translation_inverted(self): RepositoryExample.objects.create( - repository_update=self.repository.current_update(), - text='hello') + repository_update=self.repository.current_update(), text="hello" + ) example = RepositoryExample.objects.create( - repository_update=self.repository.current_update(), - text='how are you?') + repository_update=self.repository.current_update(), text="how are you?" + ) RepositoryTranslatedExample.objects.create( original_example=example, - text='com vai você?', - language=languages.LANGUAGE_PT) + text="com vai você?", + language=languages.LANGUAGE_PT, + ) RepositoryExample.objects.create( - repository_update=self.repository.current_update(), - text='hey') + repository_update=self.repository.current_update(), text="hey" + ) response, content_data = self.request( { - 'repository_uuid': self.repository.uuid, - 'order_by_translation': '-{}'.format(languages.LANGUAGE_PT), + "repository_uuid": self.repository.uuid, + "order_by_translation": "-{}".format(languages.LANGUAGE_PT), }, - self.owner_token) - results = content_data.get('results') - self.assertGreaterEqual( - 1, - len(results[0].get('translations'))) - self.assertGreaterEqual( - 1, - len(results[1].get('translations'))) - self.assertGreaterEqual( - 0, - len(results[2].get('translations'))) - self.assertGreaterEqual( - 0, - len(results[3].get('translations'))) + self.owner_token, + ) + results = content_data.get("results") + self.assertGreaterEqual(1, len(results[0].get("translations"))) + self.assertGreaterEqual(1, len(results[1].get("translations"))) + self.assertGreaterEqual(0, len(results[2].get("translations"))) + self.assertGreaterEqual(0, len(results[3].get("translations"))) def test_has_not_translation_to(self): example_1 = RepositoryExample.objects.create( - repository_update=self.repository.current_update(), - text='how are you?') + repository_update=self.repository.current_update(), text="how are you?" + ) example_2 = RepositoryExample.objects.create( - repository_update=self.repository.current_update(), - text='how are you?') + repository_update=self.repository.current_update(), text="how are you?" + ) response, content_data = self.request( { - 'repository_uuid': self.repository.uuid, - 'has_not_translation_to': languages.LANGUAGE_PT, + "repository_uuid": self.repository.uuid, + "has_not_translation_to": languages.LANGUAGE_PT, }, - self.owner_token) - self.assertEqual( - content_data.get('count'), - 2) - self.assertEqual( - content_data.get('results')[1].get('id'), - example_1.id) - self.assertEqual( - content_data.get('results')[0].get('id'), - example_2.id) + self.owner_token, + ) + self.assertEqual(content_data.get("count"), 2) + self.assertEqual(content_data.get("results")[1].get("id"), example_1.id) + self.assertEqual(content_data.get("results")[0].get("id"), example_2.id) diff --git a/bothub/api/v1/tests/test_repository.py b/bothub/api/v1/tests/test_repository.py index bbe808f2..69db896a 100644 --- a/bothub/api/v1/tests/test_repository.py +++ b/bothub/api/v1/tests/test_repository.py @@ -24,742 +24,598 @@ # TestCases + class NewRepositoryTestCase(TestCase): def setUp(self): self.factory = RequestFactory() self.user, self.token = create_user_and_token() self.authorization_header = { - 'HTTP_AUTHORIZATION': 'Token {}'.format(self.token.key), + "HTTP_AUTHORIZATION": "Token {}".format(self.token.key) } - self.category = RepositoryCategory.objects.create( - name='ID') + self.category = RepositoryCategory.objects.create(name="ID") def request(self, data): request = self.factory.post( - '/v1/repository/new/', - data, - **self.authorization_header) - response = NewRepositoryViewSet.as_view({'post': 'create'})(request) + "/v1/repository/new/", data, **self.authorization_header + ) + response = NewRepositoryViewSet.as_view({"post": "create"})(request) response.render() content_data = json.loads(response.content) - return (response, content_data,) + return (response, content_data) def test_okay(self): - response, content_data = self.request({ - 'name': 'Testing', - 'slug': 'test', - 'language': languages.LANGUAGE_EN, - 'categories': [self.category.id], - 'description': '', - }) - self.assertEqual( - response.status_code, - status.HTTP_201_CREATED) + response, content_data = self.request( + { + "name": "Testing", + "slug": "test", + "language": languages.LANGUAGE_EN, + "categories": [self.category.id], + "description": "", + } + ) + self.assertEqual(response.status_code, status.HTTP_201_CREATED) def test_fields_required(self): def request_and_check(field, data): response, content_data = self.request(data) - self.assertEqual( - response.status_code, - status.HTTP_400_BAD_REQUEST) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) self.assertIn(field, content_data.keys()) - request_and_check('name', { - 'slug': 'test', - 'language': languages.LANGUAGE_EN, - 'categories': [self.category.id], - }) - - request_and_check('slug', { - 'name': 'Testing', - 'language': languages.LANGUAGE_EN, - 'categories': [self.category.id], - }) - - request_and_check('language', { - 'name': 'Testing', - 'slug': 'test', - 'categories': [self.category.id], - }) - - request_and_check('categories', { - 'name': 'Testing', - 'slug': 'test', - 'language': languages.LANGUAGE_EN, - }) + request_and_check( + "name", + { + "slug": "test", + "language": languages.LANGUAGE_EN, + "categories": [self.category.id], + }, + ) + + request_and_check( + "slug", + { + "name": "Testing", + "language": languages.LANGUAGE_EN, + "categories": [self.category.id], + }, + ) + + request_and_check( + "language", + {"name": "Testing", "slug": "test", "categories": [self.category.id]}, + ) + + request_and_check( + "categories", + {"name": "Testing", "slug": "test", "language": languages.LANGUAGE_EN}, + ) def test_invalid_slug(self): - response, content_data = self.request({ - 'name': 'Testing', - 'slug': 'invalid slug', - 'language': languages.LANGUAGE_EN, - 'categories': [self.category.id], - }) - self.assertEqual( - response.status_code, - status.HTTP_400_BAD_REQUEST) - self.assertIn('slug', content_data.keys()) + response, content_data = self.request( + { + "name": "Testing", + "slug": "invalid slug", + "language": languages.LANGUAGE_EN, + "categories": [self.category.id], + } + ) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + self.assertIn("slug", content_data.keys()) def test_invalid_language(self): - response, content_data = self.request({ - 'name': 'Testing', - 'slug': 'test', - 'language': 'jj', - 'categories': [self.category.id], - 'description': '', - }) - self.assertEqual( - response.status_code, - status.HTTP_400_BAD_REQUEST) - self.assertIn('language', content_data.keys()) + response, content_data = self.request( + { + "name": "Testing", + "slug": "test", + "language": "jj", + "categories": [self.category.id], + "description": "", + } + ) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + self.assertIn("language", content_data.keys()) def test_unique_slug(self): - same_slug = 'test' + same_slug = "test" Repository.objects.create( owner=self.user, - name='Testing', + name="Testing", slug=same_slug, - language=languages.LANGUAGE_EN) - response, content_data = self.request({ - 'name': 'Testing', - 'slug': same_slug, - 'language': languages.LANGUAGE_EN, - 'categories': [self.category.id], - 'description': '', - }) - self.assertEqual( - response.status_code, - status.HTTP_400_BAD_REQUEST) - self.assertIn('non_field_errors', content_data.keys()) + language=languages.LANGUAGE_EN, + ) + response, content_data = self.request( + { + "name": "Testing", + "slug": same_slug, + "language": languages.LANGUAGE_EN, + "categories": [self.category.id], + "description": "", + } + ) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + self.assertIn("non_field_errors", content_data.keys()) class RetrieveRepositoryTestCase(TestCase): def setUp(self): self.factory = RequestFactory() - self.owner, self.owner_token = create_user_and_token('owner') + self.owner, self.owner_token = create_user_and_token("owner") self.user, self.user_token = create_user_and_token() self.repository = Repository.objects.create( owner=self.owner, - name='Testing', - slug='test', - language=languages.LANGUAGE_EN) + name="Testing", + slug="test", + language=languages.LANGUAGE_EN, + ) self.private_repository = Repository.objects.create( owner=self.owner, - name='Testing Private', - slug='private', + name="Testing Private", + slug="private", language=languages.LANGUAGE_EN, - is_private=True) + is_private=True, + ) def request(self, repository, token): - authorization_header = { - 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), - } + authorization_header = {"HTTP_AUTHORIZATION": "Token {}".format(token.key)} request = self.factory.get( - '/v1/repository/{}/{}/'.format( - repository.owner.nickname, - repository.slug), - **authorization_header) - response = RepositoryViewSet.as_view( - {'get': 'retrieve'})( - request, - owner__nickname=repository.owner.nickname, - slug=repository.slug) + "/v1/repository/{}/{}/".format(repository.owner.nickname, repository.slug), + **authorization_header + ) + response = RepositoryViewSet.as_view({"get": "retrieve"})( + request, owner__nickname=repository.owner.nickname, slug=repository.slug + ) response.render() content_data = json.loads(response.content) - return (response, content_data,) + return (response, content_data) def test_allowed_in_public(self): # owner - response, content_data = self.request( - self.repository, - self.owner_token) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) + response, content_data = self.request(self.repository, self.owner_token) + self.assertEqual(response.status_code, status.HTTP_200_OK) # secondary user - response, content_data = self.request( - self.repository, - self.user_token) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) + response, content_data = self.request(self.repository, self.user_token) + self.assertEqual(response.status_code, status.HTTP_200_OK) def test_allowed_in_private(self): # owner - response, content_data = self.request( - self.private_repository, - self.owner_token) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) + response, content_data = self.request(self.private_repository, self.owner_token) + self.assertEqual(response.status_code, status.HTTP_200_OK) def test_forbidden_in_private(self): # secondary user - response, content_data = self.request( - self.private_repository, - self.user_token) - self.assertEqual( - response.status_code, - status.HTTP_403_FORBIDDEN) + response, content_data = self.request(self.private_repository, self.user_token) + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) def test_languages_status(self): authorization_header = { - 'HTTP_AUTHORIZATION': 'Token {}'.format(self.user_token.key), + "HTTP_AUTHORIZATION": "Token {}".format(self.user_token.key) } request = self.factory.get( - '/v1/repository/{}/{}/languagesstatus/'.format( - self.repository.owner.nickname, - self.repository.uuid), - **authorization_header) - response = RepositoryViewSet.as_view( - {'get': 'languagesstatus'})( - request, - owner__nickname=self.repository.owner.nickname, - slug=self.repository.slug) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) + "/v1/repository/{}/{}/languagesstatus/".format( + self.repository.owner.nickname, self.repository.uuid + ), + **authorization_header + ) + response = RepositoryViewSet.as_view({"get": "languagesstatus"})( + request, + owner__nickname=self.repository.owner.nickname, + slug=self.repository.slug, + ) + self.assertEqual(response.status_code, status.HTTP_200_OK) def test_available_request_authorization(self): - response, content_data = self.request( - self.repository, - self.user_token) - self.assertTrue(content_data.get('available_request_authorization')) + response, content_data = self.request(self.repository, self.user_token) + self.assertTrue(content_data.get("available_request_authorization")) def test_owner_not_available_request_authorization(self): - response, content_data = self.request( - self.repository, - self.owner_token) - self.assertFalse(content_data.get('available_request_authorization')) + response, content_data = self.request(self.repository, self.owner_token) + self.assertFalse(content_data.get("available_request_authorization")) def test_user_not_available_request_authorization(self): authorization = self.repository.get_user_authorization(self.user) authorization.role = RepositoryAuthorization.ROLE_USER authorization.save() - response, content_data = self.request( - self.repository, - self.user_token) - self.assertFalse(content_data.get('available_request_authorization')) + response, content_data = self.request(self.repository, self.user_token) + self.assertFalse(content_data.get("available_request_authorization")) def test_requested_not_available_request_authorization(self): RequestRepositoryAuthorization.objects.create( - user=self.user, - repository=self.repository, - text='I can contribute') - response, content_data = self.request( - self.repository, - self.user_token) - self.assertFalse(content_data.get('available_request_authorization')) + user=self.user, repository=self.repository, text="I can contribute" + ) + response, content_data = self.request(self.repository, self.user_token) + self.assertFalse(content_data.get("available_request_authorization")) def test_none_request_authorization(self): - response, content_data = self.request( - self.repository, - self.user_token) - self.assertIsNone(content_data.get('request_authorization')) + response, content_data = self.request(self.repository, self.user_token) + self.assertIsNone(content_data.get("request_authorization")) def test_request_authorization(self): - text = 'I can contribute' + text = "I can contribute" request = RequestRepositoryAuthorization.objects.create( - user=self.user, - repository=self.repository, - text=text) - response, content_data = self.request( - self.repository, - self.user_token) - request_authorization = content_data.get('request_authorization') - self.assertEqual( - request_authorization.get('id'), - request.id) - self.assertEqual( - request_authorization.get('text'), - text) + user=self.user, repository=self.repository, text=text + ) + response, content_data = self.request(self.repository, self.user_token) + request_authorization = content_data.get("request_authorization") + self.assertEqual(request_authorization.get("id"), request.id) + self.assertEqual(request_authorization.get("text"), text) class UpdateRepositoryTestCase(TestCase): def setUp(self): self.factory = RequestFactory() - self.owner, self.owner_token = create_user_and_token('owner') + self.owner, self.owner_token = create_user_and_token("owner") self.user, self.user_token = create_user_and_token() - self.category = RepositoryCategory.objects.create( - name='ID') + self.category = RepositoryCategory.objects.create(name="ID") self.repository = Repository.objects.create( owner=self.owner, - name='Testing', - slug='test', - language=languages.LANGUAGE_EN) + name="Testing", + slug="test", + language=languages.LANGUAGE_EN, + ) self.repository.categories.add(self.category) def request(self, repository, token, data, partial=True): - authorization_header = { - 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), - } + authorization_header = {"HTTP_AUTHORIZATION": "Token {}".format(token.key)} request = self.factory.patch( - '/v1/repository/{}/{}/'.format( - repository.owner.nickname, - repository.slug), + "/v1/repository/{}/{}/".format(repository.owner.nickname, repository.slug), self.factory._encode_data(data, MULTIPART_CONTENT), MULTIPART_CONTENT, - **authorization_header) - response = RepositoryViewSet.as_view( - {'patch': 'update'})( - request, - owner__nickname=repository.owner.nickname, - slug=repository.slug, - partial=partial) + **authorization_header + ) + response = RepositoryViewSet.as_view({"patch": "update"})( + request, + owner__nickname=repository.owner.nickname, + slug=repository.slug, + partial=partial, + ) response.render() content_data = json.loads(response.content) - return (response, content_data,) + return (response, content_data) def test_allowed(self): - new_slug = 'test_2' + new_slug = "test_2" response, content_data = self.request( - self.repository, - self.owner_token, - {'slug': new_slug}) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) - self.assertEqual( - content_data.get('slug'), - new_slug) + self.repository, self.owner_token, {"slug": new_slug} + ) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(content_data.get("slug"), new_slug) def test_forbidden(self): - new_slug = 'test_2' + new_slug = "test_2" response, content_data = self.request( - self.repository, - self.user_token, - {'slug': new_slug}) - self.assertEqual( - response.status_code, - status.HTTP_403_FORBIDDEN) + self.repository, self.user_token, {"slug": new_slug} + ) + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) def test_update_fields(self): - new_category = RepositoryCategory.objects.create( - name='Other') + new_category = RepositoryCategory.objects.create(name="Other") mockups = [ - ( - 'name', - 'New Name', - True), - ( - 'language', - languages.LANGUAGE_PT, - True), - ( - 'categories', - [ - self.category.id, - new_category.id, - ], - True), - ( - 'description', - 'Add description', - True), - ( - 'is_private', - True, - True), - ( - 'uuid', - uuid.uuid4(), - False), - ( - 'slug', - 'test-slug', - True), + ("name", "New Name", True), + ("language", languages.LANGUAGE_PT, True), + ("categories", [self.category.id, new_category.id], True), + ("description", "Add description", True), + ("is_private", True, True), + ("uuid", uuid.uuid4(), False), + ("slug", "test-slug", True), ] - for (field, value, equal,) in mockups: + for (field, value, equal) in mockups: response, content_data = self.request( - self.repository, - self.owner_token, - {field: value}) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) + self.repository, self.owner_token, {field: value} + ) + self.assertEqual(response.status_code, status.HTTP_200_OK) if equal: - self.assertEqual( - content_data.get(field), - value) + self.assertEqual(content_data.get(field), value) else: - self.assertNotEqual( - content_data.get(field), - value) + self.assertNotEqual(content_data.get(field), value) class DestroyRepositoryTestCase(TestCase): def setUp(self): self.factory = RequestFactory() - self.owner, self.owner_token = create_user_and_token('owner') + self.owner, self.owner_token = create_user_and_token("owner") self.user, self.user_token = create_user_and_token() - self.category = RepositoryCategory.objects.create( - name='ID') + self.category = RepositoryCategory.objects.create(name="ID") self.repository = Repository.objects.create( owner=self.owner, - name='Testing', - slug='test', - language=languages.LANGUAGE_EN) + name="Testing", + slug="test", + language=languages.LANGUAGE_EN, + ) self.repository.categories.add(self.category) def request(self, repository, token): - authorization_header = { - 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), - } + authorization_header = {"HTTP_AUTHORIZATION": "Token {}".format(token.key)} request = self.factory.delete( - '/v1/repository/{}/{}/'.format( - repository.owner.nickname, - repository.slug), - **authorization_header) - response = RepositoryViewSet.as_view( - {'delete': 'destroy'})( - request, - owner__nickname=repository.owner.nickname, - slug=repository.slug) + "/v1/repository/{}/{}/".format(repository.owner.nickname, repository.slug), + **authorization_header + ) + response = RepositoryViewSet.as_view({"delete": "destroy"})( + request, owner__nickname=repository.owner.nickname, slug=repository.slug + ) response.render() return response def test_allowed(self): - response = self.request( - self.repository, - self.owner_token) - self.assertEqual( - response.status_code, - status.HTTP_204_NO_CONTENT) + response = self.request(self.repository, self.owner_token) + self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) def test_forbidden(self): - response = self.request( - self.repository, - self.user_token) - self.assertEqual( - response.status_code, - status.HTTP_403_FORBIDDEN) + response = self.request(self.repository, self.user_token) + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) class SearchRepositoriesTestCase(TestCase): def setUp(self): self.factory = RequestFactory() - self.owner, self.owner_token = create_user_and_token('owner') + self.owner, self.owner_token = create_user_and_token("owner") self.user, self.user_token = create_user_and_token() - self.category = RepositoryCategory.objects.create( - name='ID') + self.category = RepositoryCategory.objects.create(name="ID") self.repository = Repository.objects.create( owner=self.owner, - name='Testing', - slug='test', - language=languages.LANGUAGE_EN) + name="Testing", + slug="test", + language=languages.LANGUAGE_EN, + ) self.repository.categories.add(self.category) def request(self, nickname): request = self.factory.get( - '/v1/search-repositories/?nickname={}'.format(nickname) + "/v1/search-repositories/?nickname={}".format(nickname) + ) + response = SearchRepositoriesViewSet.as_view({"get": "list"})( + request, nickname=nickname ) - response = SearchRepositoriesViewSet.as_view( - {'get': 'list'} - )(request, nickname=nickname) response.render() content_data = json.loads(response.content) - return (response, content_data,) + return (response, content_data) def test_okay(self): - response, content_data = self.request('owner') + response, content_data = self.request("owner") self.assertEqual(response.status_code, 200) + self.assertEqual(content_data.get("count"), 1) self.assertEqual( - content_data.get('count'), - 1) - self.assertEqual( - uuid.UUID(content_data.get('results')[0].get('uuid')), - self.repository.uuid) + uuid.UUID(content_data.get("results")[0].get("uuid")), self.repository.uuid + ) def test_empty_with_user_okay(self): - response, content_data = self.request('fake') + response, content_data = self.request("fake") self.assertEqual(response.status_code, 200) - self.assertEqual( - content_data.get('count'), - 0) + self.assertEqual(content_data.get("count"), 0) def test_empty_without_user_okay(self): - response, content_data = self.request('') + response, content_data = self.request("") self.assertEqual(response.status_code, 200) - self.assertEqual( - content_data.get('count'), - 0) + self.assertEqual(content_data.get("count"), 0) class RepositoriesTestCase(TestCase): def setUp(self): self.factory = RequestFactory() - self.owner, self.owner_token = create_user_and_token('owner') + self.owner, self.owner_token = create_user_and_token("owner") self.user, self.user_token = create_user_and_token() - self.category = RepositoryCategory.objects.create( - name='ID') + self.category = RepositoryCategory.objects.create(name="ID") self.repository = Repository.objects.create( owner=self.owner, - name='Testing', - slug='test', - language=languages.LANGUAGE_EN) + name="Testing", + slug="test", + language=languages.LANGUAGE_EN, + ) self.repository.categories.add(self.category) self.private_repository = Repository.objects.create( owner=self.owner, - name='Private', - slug='private', + name="Private", + slug="private", language=languages.LANGUAGE_EN, - is_private=True) + is_private=True, + ) self.repository.categories.add(self.category) def request(self, data={}): - request = self.factory.get( - '/v1/repositories/', - data) - response = RepositoriesViewSet.as_view({'get': 'list'})(request) + request = self.factory.get("/v1/repositories/", data) + response = RepositoriesViewSet.as_view({"get": "list"})(request) response.render() content_data = json.loads(response.content) - return (response, content_data,) + return (response, content_data) def test_show_just_publics(self): response, content_data = self.request() + self.assertEqual(content_data.get("count"), 1) self.assertEqual( - content_data.get('count'), - 1) - self.assertEqual( - uuid.UUID(content_data.get('results')[0].get('uuid')), - self.repository.uuid) + uuid.UUID(content_data.get("results")[0].get("uuid")), self.repository.uuid + ) def test_filter_by_name(self): - response, content_data = self.request({ - 'search': 'Test', - }) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) - self.assertEqual( - content_data.get('count'), - 1) + response, content_data = self.request({"search": "Test"}) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(content_data.get("count"), 1) - response, content_data = self.request({ - 'search': 'z', - }) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) - self.assertEqual( - content_data.get('count'), - 0) + response, content_data = self.request({"search": "z"}) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(content_data.get("count"), 0) class TrainRepositoryTestCase(TestCase): def setUp(self): self.factory = RequestFactory() - self.owner, self.owner_token = create_user_and_token('owner') + self.owner, self.owner_token = create_user_and_token("owner") self.user, self.user_token = create_user_and_token() self.repository = Repository.objects.create( owner=self.owner, - name='Testing', - slug='test', - language=languages.LANGUAGE_EN) + name="Testing", + slug="test", + language=languages.LANGUAGE_EN, + ) def request(self, repository, token): - authorization_header = { - 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), - } + authorization_header = {"HTTP_AUTHORIZATION": "Token {}".format(token.key)} request = self.factory.get( - '/v1/repository/{}/{}/train/'.format( - repository.owner.nickname, - repository.slug), - **authorization_header) - response = RepositoryViewSet.as_view({'get': 'train'})(request) + "/v1/repository/{}/{}/train/".format( + repository.owner.nickname, repository.slug + ), + **authorization_header + ) + response = RepositoryViewSet.as_view({"get": "train"})(request) response.render() content_data = json.loads(response.content) - return (response, content_data,) + return (response, content_data) def test_permission_denied(self): response, content_data = self.request(self.repository, self.user_token) - self.assertEqual( - response.status_code, - status.HTTP_403_FORBIDDEN) + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) class AnalyzeRepositoryTestCase(TestCase): def setUp(self): self.factory = RequestFactory() - self.owner, self.owner_token = create_user_and_token('owner') + self.owner, self.owner_token = create_user_and_token("owner") self.user, self.user_token = create_user_and_token() self.repository = Repository.objects.create( owner=self.owner, - name='Testing', - slug='test', - language=languages.LANGUAGE_EN) + name="Testing", + slug="test", + language=languages.LANGUAGE_EN, + ) self.private_repository = Repository.objects.create( owner=self.owner, - name='Testing', - slug='private', + name="Testing", + slug="private", language=languages.LANGUAGE_EN, - is_private=True) + is_private=True, + ) def request(self, repository, token, data): - authorization_header = { - 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), - } + authorization_header = {"HTTP_AUTHORIZATION": "Token {}".format(token.key)} request = self.factory.post( - '/v1/repository/{}/{}/analyze/'.format( - repository.owner.nickname, - repository.slug), + "/v1/repository/{}/{}/analyze/".format( + repository.owner.nickname, repository.slug + ), data, - **authorization_header) - response = RepositoryViewSet.as_view({'post': 'analyze'})( - request, - owner__nickname=repository.owner.nickname, - slug=repository.slug) + **authorization_header + ) + response = RepositoryViewSet.as_view({"post": "analyze"})( + request, owner__nickname=repository.owner.nickname, slug=repository.slug + ) response.render() content_data = json.loads(response.content) - return (response, content_data,) + return (response, content_data) def test_permission_denied_in_private_repository(self): response, content_data = self.request( self.private_repository, self.user_token, - { - 'language': 'en', - 'text': 'My name is user', - }) - self.assertEqual( - response.status_code, - status.HTTP_403_FORBIDDEN) + {"language": "en", "text": "My name is user"}, + ) + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) def test_language_required(self): response, content_data = self.request( self.repository, self.owner_token, - { - 'language': '', - 'text': 'My name is user', - }) - self.assertEqual( - response.status_code, - status.HTTP_400_BAD_REQUEST) - self.assertIn('language', content_data.keys()) + {"language": "", "text": "My name is user"}, + ) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + self.assertIn("language", content_data.keys()) def test_text_required(self): response, content_data = self.request( - self.repository, - self.owner_token, - { - 'language': 'en', - 'text': '', - }) - self.assertEqual( - response.status_code, - status.HTTP_400_BAD_REQUEST) - self.assertIn('text', content_data.keys()) + self.repository, self.owner_token, {"language": "en", "text": ""} + ) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + self.assertIn("text", content_data.keys()) class LanguagesStatusTestCase(TestCase): def setUp(self): self.factory = RequestFactory() - self.owner, self.owner_token = create_user_and_token('owner') + self.owner, self.owner_token = create_user_and_token("owner") self.user, self.user_token = create_user_and_token() self.repository = Repository.objects.create( owner=self.owner, - name='Testing', - slug='test', - language=languages.LANGUAGE_EN) + name="Testing", + slug="test", + language=languages.LANGUAGE_EN, + ) self.example_1 = RepositoryExample.objects.create( - repository_update=self.repository.current_update( - languages.LANGUAGE_EN), - text='hi', - intent='greet') + repository_update=self.repository.current_update(languages.LANGUAGE_EN), + text="hi", + intent="greet", + ) self.example_2 = RepositoryExample.objects.create( - repository_update=self.repository.current_update( - languages.LANGUAGE_EN), - text='Here is London', - intent='place') + repository_update=self.repository.current_update(languages.LANGUAGE_EN), + text="Here is London", + intent="place", + ) self.example_3 = RepositoryExample.objects.create( - repository_update=self.repository.current_update( - languages.LANGUAGE_EN), - text='Here is Brazil', - intent='place') + repository_update=self.repository.current_update(languages.LANGUAGE_EN), + text="Here is Brazil", + intent="place", + ) def request(self, repository, token): - authorization_header = { - 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), - } + authorization_header = {"HTTP_AUTHORIZATION": "Token {}".format(token.key)} request = self.factory.get( - '/v1/repository/{}/{}/languagesstatus/'.format( - repository.owner.nickname, - repository.slug), - **authorization_header) - response = RepositoryViewSet.as_view( - {'get': 'languagesstatus'})(request) + "/v1/repository/{}/{}/languagesstatus/".format( + repository.owner.nickname, repository.slug + ), + **authorization_header + ) + response = RepositoryViewSet.as_view({"get": "languagesstatus"})(request) response.render() content_data = json.loads(response.content) - return (response, content_data,) + return (response, content_data) def test_okay(self): - response, content_data = self.request( - self.repository, - self.owner_token) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) + response, content_data = self.request(self.repository, self.owner_token) + self.assertEqual(response.status_code, status.HTTP_200_OK) def test_unique_entities(self): RepositoryExampleEntity.objects.create( - repository_example=self.example_1, - start=0, - end=0, - entity='entity1') + repository_example=self.example_1, start=0, end=0, entity="entity1" + ) RepositoryExampleEntity.objects.create( - repository_example=self.example_2, - start=0, - end=0, - entity='entity1') + repository_example=self.example_2, start=0, end=0, entity="entity1" + ) RepositoryExampleEntity.objects.create( - repository_example=self.example_3, - start=0, - end=0, - entity='entity2') + repository_example=self.example_3, start=0, end=0, entity="entity2" + ) counter = {} - response, content_data = self.request( - self.repository, - self.owner_token) - languages_status = content_data.get('languages_status') + response, content_data = self.request(self.repository, self.owner_token) + languages_status = content_data.get("languages_status") for language in languages_status: language_status = languages_status.get(language) - for entity in language_status.get('examples').get('entities'): + for entity in language_status.get("examples").get("entities"): counter[entity] = counter.get(entity, 0) + 1 self.failIfEqual(counter.get(entity), 2) def test_none_entities(self): - response, content_data = self.request( - self.repository, - self.owner_token) - languages_status = content_data.get('languages_status') + response, content_data = self.request(self.repository, self.owner_token) + languages_status = content_data.get("languages_status") for language in languages_status: language_status = languages_status.get(language) - for entity in language_status.get('examples').get('entities'): + for entity in language_status.get("examples").get("entities"): self.failIfEqual(entity, None) diff --git a/bothub/api/v1/tests/test_request.py b/bothub/api/v1/tests/test_request.py index e74c3000..b8afcc29 100644 --- a/bothub/api/v1/tests/test_request.py +++ b/bothub/api/v1/tests/test_request.py @@ -20,236 +20,189 @@ class RequestAuthorizationTestCase(TestCase): def setUp(self): self.factory = RequestFactory() - self.owner, self.owner_token = create_user_and_token('owner') + self.owner, self.owner_token = create_user_and_token("owner") self.user, self.token = create_user_and_token() self.repository = Repository.objects.create( owner=self.owner, - name='Testing', - slug='test', - language=languages.LANGUAGE_EN) + name="Testing", + slug="test", + language=languages.LANGUAGE_EN, + ) def request(self, data, token=None): - authorization_header = { - 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), - } if token else {} + authorization_header = ( + {"HTTP_AUTHORIZATION": "Token {}".format(token.key)} if token else {} + ) request = self.factory.post( - '/v1/request-authorization/', - data, - **authorization_header) - response = RequestAuthorizationViewSet.as_view( - {'post': 'create'})(request) + "/v1/request-authorization/", data, **authorization_header + ) + response = RequestAuthorizationViewSet.as_view({"post": "create"})(request) response.render() content_data = json.loads(response.content) - return (response, content_data,) + return (response, content_data) def test_okay(self): - response, content_data = self.request({ - 'repository': self.repository.uuid, - 'text': 'I can contribute', - }, self.token) - self.assertEqual( - response.status_code, - status.HTTP_201_CREATED) + response, content_data = self.request( + {"repository": self.repository.uuid, "text": "I can contribute"}, self.token + ) + self.assertEqual(response.status_code, status.HTTP_201_CREATED) def test_forbidden_two_requests(self): RequestRepositoryAuthorization.objects.create( - user=self.user, - repository=self.repository, - text='I can contribute') - response, content_data = self.request({ - 'repository': self.repository.uuid, - 'text': 'I can contribute', - }, self.token) - self.assertEqual( - response.status_code, - status.HTTP_400_BAD_REQUEST) - self.assertIn( - 'non_field_errors', - content_data.keys()) + user=self.user, repository=self.repository, text="I can contribute" + ) + response, content_data = self.request( + {"repository": self.repository.uuid, "text": "I can contribute"}, self.token + ) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + self.assertIn("non_field_errors", content_data.keys()) class RepositoryAuthorizationRequestsTestCase(TestCase): def setUp(self): self.factory = RequestFactory() - self.owner, self.owner_token = create_user_and_token('owner') - self.admin, self.admin_token = create_user_and_token('admin') + self.owner, self.owner_token = create_user_and_token("owner") + self.admin, self.admin_token = create_user_and_token("admin") self.user, self.user_token = create_user_and_token() self.repository = Repository.objects.create( owner=self.owner, - name='Testing', - slug='test', - language=languages.LANGUAGE_EN) + name="Testing", + slug="test", + language=languages.LANGUAGE_EN, + ) RequestRepositoryAuthorization.objects.create( - user=self.user, - repository=self.repository, - text='I can contribute') + user=self.user, repository=self.repository, text="I can contribute" + ) admin_autho = self.repository.get_user_authorization(self.admin) admin_autho.role = RepositoryAuthorization.ROLE_ADMIN admin_autho.save() def request(self, data, token=None): - authorization_header = { - 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), - } if token else {} + authorization_header = ( + {"HTTP_AUTHORIZATION": "Token {}".format(token.key)} if token else {} + ) request = self.factory.get( - '/v1/authorization-requests/', - data, - **authorization_header) - response = RepositoryAuthorizationRequestsViewSet.as_view( - {'get': 'list'})(request) + "/v1/authorization-requests/", data, **authorization_header + ) + response = RepositoryAuthorizationRequestsViewSet.as_view({"get": "list"})( + request + ) response.render() content_data = json.loads(response.content) - return (response, content_data,) + return (response, content_data) def test_okay(self): - response, content_data = self.request({ - 'repository_uuid': self.repository.uuid, - }, self.owner_token) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) - self.assertEqual( - content_data.get('count'), - 1) + response, content_data = self.request( + {"repository_uuid": self.repository.uuid}, self.owner_token + ) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(content_data.get("count"), 1) def test_admin_okay(self): - response, content_data = self.request({ - 'repository_uuid': self.repository.uuid, - }, self.admin_token) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) - self.assertEqual( - content_data.get('count'), - 1) + response, content_data = self.request( + {"repository_uuid": self.repository.uuid}, self.admin_token + ) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(content_data.get("count"), 1) def test_repository_uuid_empty(self): response, content_data = self.request({}, self.owner_token) - self.assertEqual( - response.status_code, - status.HTTP_400_BAD_REQUEST) - self.assertEqual( - len(content_data.get('repository_uuid')), - 1) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + self.assertEqual(len(content_data.get("repository_uuid")), 1) def test_forbidden(self): - response, content_data = self.request({ - 'repository_uuid': self.repository.uuid, - }, self.user_token) - self.assertEqual( - response.status_code, - status.HTTP_403_FORBIDDEN) + response, content_data = self.request( + {"repository_uuid": self.repository.uuid}, self.user_token + ) + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) class ReviewAuthorizationRequestTestCase(TestCase): def setUp(self): self.factory = RequestFactory() - self.owner, self.owner_token = create_user_and_token('owner') - self.admin, self.admin_token = create_user_and_token('admin') + self.owner, self.owner_token = create_user_and_token("owner") + self.admin, self.admin_token = create_user_and_token("admin") self.user, self.user_token = create_user_and_token() repository = Repository.objects.create( owner=self.owner, - name='Testing', - slug='test', - language=languages.LANGUAGE_EN) + name="Testing", + slug="test", + language=languages.LANGUAGE_EN, + ) self.ra = RequestRepositoryAuthorization.objects.create( - user=self.user, - repository=repository, - text='I can contribute') + user=self.user, repository=repository, text="I can contribute" + ) admin_autho = repository.get_user_authorization(self.admin) admin_autho.role = RepositoryAuthorization.ROLE_ADMIN admin_autho.save() def request_approve(self, ra, token=None): - authorization_header = { - 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), - } if token else {} + authorization_header = ( + {"HTTP_AUTHORIZATION": "Token {}".format(token.key)} if token else {} + ) request = self.factory.put( - '/v1/review-authorization-request/{}/'.format(ra.pk), + "/v1/review-authorization-request/{}/".format(ra.pk), self.factory._encode_data({}, MULTIPART_CONTENT), MULTIPART_CONTENT, - **authorization_header) - response = ReviewAuthorizationRequestViewSet.as_view( - {'put': 'update'})(request, pk=ra.pk) + **authorization_header + ) + response = ReviewAuthorizationRequestViewSet.as_view({"put": "update"})( + request, pk=ra.pk + ) response.render() content_data = json.loads(response.content) - return (response, content_data,) + return (response, content_data) def request_reject(self, ra, token=None): - authorization_header = { - 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), - } if token else {} + authorization_header = ( + {"HTTP_AUTHORIZATION": "Token {}".format(token.key)} if token else {} + ) request = self.factory.delete( - '/v1/review-authorization-request/{}/'.format(ra.pk), - **authorization_header) - response = ReviewAuthorizationRequestViewSet.as_view( - {'delete': 'destroy'})(request, pk=ra.pk) + "/v1/review-authorization-request/{}/".format(ra.pk), **authorization_header + ) + response = ReviewAuthorizationRequestViewSet.as_view({"delete": "destroy"})( + request, pk=ra.pk + ) response.render() return response def test_approve_okay(self): - response, content_data = self.request_approve( - self.ra, - self.owner_token) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) - self.assertEqual( - content_data.get('approved_by'), - self.owner.id) + response, content_data = self.request_approve(self.ra, self.owner_token) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(content_data.get("approved_by"), self.owner.id) def test_admin_approve_okay(self): - response, content_data = self.request_approve( - self.ra, - self.admin_token) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) - self.assertEqual( - content_data.get('approved_by'), - self.admin.id) + response, content_data = self.request_approve(self.ra, self.admin_token) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(content_data.get("approved_by"), self.admin.id) def test_approve_twice(self): self.ra.approved_by = self.owner self.ra.save() - response, content_data = self.request_approve( - self.ra, - self.owner_token) - self.assertEqual( - response.status_code, - status.HTTP_400_BAD_REQUEST) + response, content_data = self.request_approve(self.ra, self.owner_token) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) def test_approve_forbidden(self): - response, content_data = self.request_approve( - self.ra, - self.user_token) - self.assertEqual( - response.status_code, - status.HTTP_403_FORBIDDEN) + response, content_data = self.request_approve(self.ra, self.user_token) + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) def test_reject_okay(self): response = self.request_reject(self.ra, self.owner_token) - self.assertEqual( - response.status_code, - status.HTTP_204_NO_CONTENT) + self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) def test_admin_reject_okay(self): response = self.request_reject(self.ra, self.admin_token) - self.assertEqual( - response.status_code, - status.HTTP_204_NO_CONTENT) + self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) def test_reject_forbidden(self): response = self.request_reject(self.ra, self.user_token) - self.assertEqual( - response.status_code, - status.HTTP_403_FORBIDDEN) + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) diff --git a/bothub/api/v1/tests/test_translate.py b/bothub/api/v1/tests/test_translate.py index 2f646af4..7fce2006 100644 --- a/bothub/api/v1/tests/test_translate.py +++ b/bothub/api/v1/tests/test_translate.py @@ -22,474 +22,373 @@ class TranslateExampleTestCase(TestCase): def setUp(self): self.factory = RequestFactory() - self.owner, self.owner_token = create_user_and_token('owner') + self.owner, self.owner_token = create_user_and_token("owner") self.repository = Repository.objects.create( owner=self.owner, - name='Testing', - slug='test', - language=languages.LANGUAGE_EN) + name="Testing", + slug="test", + language=languages.LANGUAGE_EN, + ) self.example = RepositoryExample.objects.create( - repository_update=self.repository.current_update(), - text='hi') + repository_update=self.repository.current_update(), text="hi" + ) def request(self, data, user_token): - authorization_header = { - 'HTTP_AUTHORIZATION': 'Token {}'.format(user_token.key), - } + authorization_header = {"HTTP_AUTHORIZATION": "Token {}".format(user_token.key)} request = self.factory.post( - '/v1/translate-example/', + "/v1/translate-example/", json.dumps(data), - content_type='application/json', - **authorization_header) - response = NewRepositoryTranslatedExampleViewSet.as_view( - {'post': 'create'})(request) + content_type="application/json", + **authorization_header + ) + response = NewRepositoryTranslatedExampleViewSet.as_view({"post": "create"})( + request + ) response.render() content_data = json.loads(response.content) - return (response, content_data,) + return (response, content_data) def test_okay(self): response, content_data = self.request( { - 'original_example': self.example.id, - 'language': languages.LANGUAGE_PT, - 'text': 'oi', - 'entities': [], + "original_example": self.example.id, + "language": languages.LANGUAGE_PT, + "text": "oi", + "entities": [], }, - self.owner_token) - self.assertEqual( - response.status_code, - status.HTTP_201_CREATED) + self.owner_token, + ) + self.assertEqual(response.status_code, status.HTTP_201_CREATED) def test_unique_translate(self): language = languages.LANGUAGE_PT - text = 'oi' + text = "oi" RepositoryTranslatedExample.objects.create( - original_example=self.example, - language=language, - text=text) + original_example=self.example, language=language, text=text + ) response, content_data = self.request( { - 'original_example': self.example.id, - 'language': language, - 'text': text, - 'entities': [], + "original_example": self.example.id, + "language": language, + "text": text, + "entities": [], }, - self.owner_token) - self.assertEqual( - response.status_code, - status.HTTP_400_BAD_REQUEST) - self.assertIn( - 'non_field_errors', - content_data.keys()) + self.owner_token, + ) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + self.assertIn("non_field_errors", content_data.keys()) def test_forbidden(self): user, user_token = create_user_and_token() response, content_data = self.request( { - 'original_example': self.example.id, - 'language': languages.LANGUAGE_PT, - 'text': 'oi', - 'entities': [], + "original_example": self.example.id, + "language": languages.LANGUAGE_PT, + "text": "oi", + "entities": [], }, - user_token) - self.assertEqual( - response.status_code, - status.HTTP_403_FORBIDDEN) + user_token, + ) + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) def test_okay_with_entities(self): example = RepositoryExample.objects.create( - repository_update=self.repository.current_update(), - text='my name is user') + repository_update=self.repository.current_update(), text="my name is user" + ) RepositoryExampleEntity.objects.create( - repository_example=example, - start=11, - end=18, - entity='name') + repository_example=example, start=11, end=18, entity="name" + ) response, content_data = self.request( { - 'original_example': example.id, - 'language': languages.LANGUAGE_PT, - 'text': 'meu nome é user', - 'entities': [ - { - 'start': 11, - 'end': 18, - 'entity': 'name', - }, - ], + "original_example": example.id, + "language": languages.LANGUAGE_PT, + "text": "meu nome é user", + "entities": [{"start": 11, "end": 18, "entity": "name"}], }, - self.owner_token) - self.assertEqual( - response.status_code, - status.HTTP_201_CREATED) - self.assertEqual( - len(content_data.get('entities')), - 1) + self.owner_token, + ) + self.assertEqual(response.status_code, status.HTTP_201_CREATED) + self.assertEqual(len(content_data.get("entities")), 1) def test_entities_no_valid(self): example = RepositoryExample.objects.create( - repository_update=self.repository.current_update(), - text='my name is user') + repository_update=self.repository.current_update(), text="my name is user" + ) RepositoryExampleEntity.objects.create( - repository_example=self.example, - start=11, - end=18, - entity='name') + repository_example=self.example, start=11, end=18, entity="name" + ) response, content_data = self.request( { - 'original_example': example.id, - 'language': languages.LANGUAGE_PT, - 'text': 'meu nome é user', - 'entities': [ - { - 'start': 11, - 'end': 18, - 'entity': 'nome', - }, - ], + "original_example": example.id, + "language": languages.LANGUAGE_PT, + "text": "meu nome é user", + "entities": [{"start": 11, "end": 18, "entity": "nome"}], }, - self.owner_token) - self.assertEqual( - response.status_code, - status.HTTP_400_BAD_REQUEST) - self.assertEqual( - len(content_data.get('entities')), - 1) + self.owner_token, + ) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + self.assertEqual(len(content_data.get("entities")), 1) def test_entities_no_valid_2(self): example = RepositoryExample.objects.create( - repository_update=self.repository.current_update(), - text='my name is user') + repository_update=self.repository.current_update(), text="my name is user" + ) RepositoryExampleEntity.objects.create( - repository_example=self.example, - start=11, - end=18, - entity='name') + repository_example=self.example, start=11, end=18, entity="name" + ) response, content_data = self.request( { - 'original_example': example.id, - 'language': languages.LANGUAGE_PT, - 'text': 'meu nome é user', - 'entities': [ - { - 'start': 11, - 'end': 18, - 'entity': 'name', - }, - { - 'start': 0, - 'end': 3, - 'entity': 'my', - }, + "original_example": example.id, + "language": languages.LANGUAGE_PT, + "text": "meu nome é user", + "entities": [ + {"start": 11, "end": 18, "entity": "name"}, + {"start": 0, "end": 3, "entity": "my"}, ], }, - self.owner_token) - self.assertEqual( - response.status_code, - status.HTTP_400_BAD_REQUEST) - self.assertEqual( - len(content_data.get('entities')), - 1) + self.owner_token, + ) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + self.assertEqual(len(content_data.get("entities")), 1) def test_can_not_translate_to_same_language(self): response, content_data = self.request( { - 'original_example': self.example.id, - 'language': self.example.repository_update.language, - 'text': 'oi', - 'entities': [], + "original_example": self.example.id, + "language": self.example.repository_update.language, + "text": "oi", + "entities": [], }, - self.owner_token) - self.assertEqual( - response.status_code, - status.HTTP_400_BAD_REQUEST) - self.assertIn( - 'language', - content_data.keys()) + self.owner_token, + ) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + self.assertIn("language", content_data.keys()) class RepositoryTranslatedExampleRetrieveTestCase(TestCase): def setUp(self): self.factory = RequestFactory() - self.owner, self.owner_token = create_user_and_token('owner') + self.owner, self.owner_token = create_user_and_token("owner") self.repository = Repository.objects.create( owner=self.owner, - name='Testing', - slug='test', - language=languages.LANGUAGE_EN) + name="Testing", + slug="test", + language=languages.LANGUAGE_EN, + ) self.example = RepositoryExample.objects.create( - repository_update=self.repository.current_update(), - text='hi') + repository_update=self.repository.current_update(), text="hi" + ) self.translated = RepositoryTranslatedExample.objects.create( - original_example=self.example, - language=languages.LANGUAGE_PT, - text='oi') + original_example=self.example, language=languages.LANGUAGE_PT, text="oi" + ) self.private_repository = Repository.objects.create( owner=self.owner, - name='Private', - slug='private', + name="Private", + slug="private", language=languages.LANGUAGE_EN, - is_private=True) + is_private=True, + ) self.private_example = RepositoryExample.objects.create( - repository_update=self.private_repository.current_update(), - text='hi') + repository_update=self.private_repository.current_update(), text="hi" + ) self.private_translated = RepositoryTranslatedExample.objects.create( original_example=self.private_example, language=languages.LANGUAGE_PT, - text='oi') + text="oi", + ) def request(self, translated, token): - authorization_header = { - 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), - } + authorization_header = {"HTTP_AUTHORIZATION": "Token {}".format(token.key)} request = self.factory.get( - '/v1/translation/{}/'.format(translated.id), - **authorization_header) - response = RepositoryTranslatedExampleViewSet.as_view( - {'get': 'retrieve'})(request, pk=translated.id) + "/v1/translation/{}/".format(translated.id), **authorization_header + ) + response = RepositoryTranslatedExampleViewSet.as_view({"get": "retrieve"})( + request, pk=translated.id + ) response.render() content_data = json.loads(response.content) - return (response, content_data,) + return (response, content_data) def test_okay(self): - response, content_data = self.request( - self.translated, - self.owner_token) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) - self.assertEqual( - content_data.get('id'), - self.translated.id) + response, content_data = self.request(self.translated, self.owner_token) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(content_data.get("id"), self.translated.id) def test_private_okay(self): - response, content_data = self.request( - self.private_translated, - self.owner_token) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) - self.assertEqual( - content_data.get('id'), - self.private_translated.id) + response, content_data = self.request(self.private_translated, self.owner_token) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(content_data.get("id"), self.private_translated.id) def test_forbidden(self): user, user_token = create_user_and_token() - response, content_data = self.request( - self.private_translated, - user_token) - self.assertEqual( - response.status_code, - status.HTTP_403_FORBIDDEN) + response, content_data = self.request(self.private_translated, user_token) + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) class RepositoryTranslatedExampleDestroyTestCase(TestCase): def setUp(self): self.factory = RequestFactory() - self.owner, self.owner_token = create_user_and_token('owner') + self.owner, self.owner_token = create_user_and_token("owner") self.repository = Repository.objects.create( owner=self.owner, - name='Testing', - slug='test', - language=languages.LANGUAGE_EN) + name="Testing", + slug="test", + language=languages.LANGUAGE_EN, + ) self.example = RepositoryExample.objects.create( - repository_update=self.repository.current_update(), - text='hi') + repository_update=self.repository.current_update(), text="hi" + ) self.translated = RepositoryTranslatedExample.objects.create( - original_example=self.example, - language=languages.LANGUAGE_PT, - text='oi') + original_example=self.example, language=languages.LANGUAGE_PT, text="oi" + ) def request(self, translated, token): - authorization_header = { - 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), - } + authorization_header = {"HTTP_AUTHORIZATION": "Token {}".format(token.key)} request = self.factory.delete( - '/v1/translation/{}/'.format(translated.id), - **authorization_header) - response = RepositoryTranslatedExampleViewSet.as_view( - {'delete': 'destroy'})(request, pk=translated.id) + "/v1/translation/{}/".format(translated.id), **authorization_header + ) + response = RepositoryTranslatedExampleViewSet.as_view({"delete": "destroy"})( + request, pk=translated.id + ) return response def test_okay(self): - response = self.request( - self.translated, - self.owner_token) - self.assertEqual( - response.status_code, - status.HTTP_204_NO_CONTENT) + response = self.request(self.translated, self.owner_token) + self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) def test_forbidden(self): user, user_token = create_user_and_token() - response = self.request( - self.translated, - user_token) - self.assertEqual( - response.status_code, - status.HTTP_403_FORBIDDEN) + response = self.request(self.translated, user_token) + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) class TranslationsViewTest(TestCase): def setUp(self): self.factory = RequestFactory() - self.owner, self.owner_token = create_user_and_token('owner') + self.owner, self.owner_token = create_user_and_token("owner") self.repository = Repository.objects.create( owner=self.owner, - name='Testing', - slug='test', - language=languages.LANGUAGE_EN) + name="Testing", + slug="test", + language=languages.LANGUAGE_EN, + ) self.example = RepositoryExample.objects.create( - repository_update=self.repository.current_update(), - text='hi') + repository_update=self.repository.current_update(), text="hi" + ) self.translated = RepositoryTranslatedExample.objects.create( - original_example=self.example, - language=languages.LANGUAGE_PT, - text='oi') + original_example=self.example, language=languages.LANGUAGE_PT, text="oi" + ) def request(self, data, user_token=None): - authorization_header = { - 'HTTP_AUTHORIZATION': 'Token {}'.format(user_token.key), - } if user_token else {} - request = self.factory.get( - '/v1/translations/', - data, - **authorization_header) - response = TranslationsViewSet.as_view({'get': 'list'})(request) + authorization_header = ( + {"HTTP_AUTHORIZATION": "Token {}".format(user_token.key)} + if user_token + else {} + ) + request = self.factory.get("/v1/translations/", data, **authorization_header) + response = TranslationsViewSet.as_view({"get": "list"})(request) response.render() content_data = json.loads(response.content) - return (response, content_data,) + return (response, content_data) def test_okay(self): - response, content_data = self.request({ - 'repository_uuid': self.repository.uuid, - }) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) - self.assertEqual( - content_data.get('count'), - 1) + response, content_data = self.request({"repository_uuid": self.repository.uuid}) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(content_data.get("count"), 1) def test_repository_not_found(self): - response, content_data = self.request({ - 'repository_uuid': uuid.uuid4(), - }) - self.assertEqual( - response.status_code, - status.HTTP_404_NOT_FOUND) + response, content_data = self.request({"repository_uuid": uuid.uuid4()}) + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) def test_repository_uuid_invalid(self): - response, content_data = self.request({ - 'repository_uuid': 'invalid', - }) - self.assertEqual( - response.status_code, - status.HTTP_404_NOT_FOUND) + response, content_data = self.request({"repository_uuid": "invalid"}) + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) def test_forbidden(self): private_repository = Repository.objects.create( owner=self.owner, - name='Testing', - slug='private', + name="Testing", + slug="private", language=languages.LANGUAGE_EN, - is_private=True) + is_private=True, + ) - response, content_data = self.request({ - 'repository_uuid': private_repository.uuid, - }) - self.assertEqual( - response.status_code, - status.HTTP_403_FORBIDDEN) + response, content_data = self.request( + {"repository_uuid": private_repository.uuid} + ) + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) - user, user_token = create_user_and_token('user') + user, user_token = create_user_and_token("user") response, content_data = self.request( - { - 'repository_uuid': private_repository.uuid, - }, - user_token) - self.assertEqual( - response.status_code, - status.HTTP_403_FORBIDDEN) + {"repository_uuid": private_repository.uuid}, user_token + ) + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) def test_filter_from_language(self): example = RepositoryExample.objects.create( - repository_update=self.repository.current_update( - languages.LANGUAGE_ES), - text='hola') + repository_update=self.repository.current_update(languages.LANGUAGE_ES), + text="hola", + ) translated = RepositoryTranslatedExample.objects.create( - original_example=example, - language=languages.LANGUAGE_PT, - text='oi') - - response, content_data = self.request({ - 'repository_uuid': self.repository.uuid, - 'from_language': self.example.repository_update.language, - }) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) - self.assertEqual( - content_data.get('count'), - 1) - self.assertEqual( - content_data.get('results')[0].get('id'), - self.translated.id) - - response, content_data = self.request({ - 'repository_uuid': self.repository.uuid, - 'from_language': example.repository_update.language, - }) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) - self.assertEqual( - content_data.get('count'), - 1) - self.assertEqual( - content_data.get('results')[0].get('id'), - translated.id) + original_example=example, language=languages.LANGUAGE_PT, text="oi" + ) + + response, content_data = self.request( + { + "repository_uuid": self.repository.uuid, + "from_language": self.example.repository_update.language, + } + ) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(content_data.get("count"), 1) + self.assertEqual(content_data.get("results")[0].get("id"), self.translated.id) + + response, content_data = self.request( + { + "repository_uuid": self.repository.uuid, + "from_language": example.repository_update.language, + } + ) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(content_data.get("count"), 1) + self.assertEqual(content_data.get("results")[0].get("id"), translated.id) def test_filter_to_language(self): example = RepositoryExample.objects.create( - repository_update=self.repository.current_update( - languages.LANGUAGE_ES), - text='hola') + repository_update=self.repository.current_update(languages.LANGUAGE_ES), + text="hola", + ) RepositoryTranslatedExample.objects.create( - original_example=example, - language=languages.LANGUAGE_PT, - text='oi') - - response, content_data = self.request({ - 'repository_uuid': self.repository.uuid, - 'to_language': self.translated.language, - }) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) - self.assertEqual( - content_data.get('count'), - 2) - - response, content_data = self.request({ - 'repository_uuid': self.repository.uuid, - 'to_language': languages.LANGUAGE_DE, - }) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) - self.assertEqual( - content_data.get('count'), - 0) + original_example=example, language=languages.LANGUAGE_PT, text="oi" + ) + + response, content_data = self.request( + { + "repository_uuid": self.repository.uuid, + "to_language": self.translated.language, + } + ) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(content_data.get("count"), 2) + + response, content_data = self.request( + { + "repository_uuid": self.repository.uuid, + "to_language": languages.LANGUAGE_DE, + } + ) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(content_data.get("count"), 0) diff --git a/bothub/api/v1/tests/test_updates.py b/bothub/api/v1/tests/test_updates.py index 84b78b60..381cf54c 100644 --- a/bothub/api/v1/tests/test_updates.py +++ b/bothub/api/v1/tests/test_updates.py @@ -15,64 +15,46 @@ class UpdatesTestCase(TestCase): def setUp(self): self.factory = RequestFactory() - self.owner, self.owner_token = create_user_and_token('owner') + self.owner, self.owner_token = create_user_and_token("owner") self.repository = Repository.objects.create( owner=self.owner, - name='Testing', - slug='test', - language=languages.LANGUAGE_EN) + name="Testing", + slug="test", + language=languages.LANGUAGE_EN, + ) current_update = self.repository.current_update() RepositoryExample.objects.create( - repository_update=current_update, - text='my name is user', - intent='greet') + repository_update=current_update, text="my name is user", intent="greet" + ) RepositoryExample.objects.create( - repository_update=current_update, - text='my name is John', - intent='greet') + repository_update=current_update, text="my name is John", intent="greet" + ) current_update.start_training(self.owner) def request(self, data, token=None): - authorization_header = { - 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), - } if token else {} - request = self.factory.get( - '/v1/updates/', - data, - **authorization_header) - response = RepositoryUpdatesViewSet.as_view( - {'get': 'list'})(request) + authorization_header = ( + {"HTTP_AUTHORIZATION": "Token {}".format(token.key)} if token else {} + ) + request = self.factory.get("/v1/updates/", data, **authorization_header) + response = RepositoryUpdatesViewSet.as_view({"get": "list"})(request) response.render() content_data = json.loads(response.content) - return (response, content_data,) + return (response, content_data) def test_okay(self): response, content_data = self.request( - { - 'repository_uuid': str(self.repository.uuid), - }, - self.owner_token) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) - self.assertEqual( - content_data.get('count'), - 1) + {"repository_uuid": str(self.repository.uuid)}, self.owner_token + ) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(content_data.get("count"), 1) def test_not_authenticated(self): response, content_data = self.request( - { - 'repository_uuid': str(self.repository.uuid), - }) - self.assertEqual( - response.status_code, - status.HTTP_401_UNAUTHORIZED) + {"repository_uuid": str(self.repository.uuid)} + ) + self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED) def test_without_repository(self): - response, content_data = self.request( - {}, - self.owner_token) - self.assertEqual( - response.status_code, - status.HTTP_400_BAD_REQUEST) + response, content_data = self.request({}, self.owner_token) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) diff --git a/bothub/api/v1/tests/test_user.py b/bothub/api/v1/tests/test_user.py index 11a656b8..b6651b88 100644 --- a/bothub/api/v1/tests/test_user.py +++ b/bothub/api/v1/tests/test_user.py @@ -22,81 +22,63 @@ def setUp(self): self.factory = RequestFactory() def request(self, data): - request = self.factory.post( - '/v1/register/', - data) - response = RegisterUserViewSet.as_view( - {'post': 'create'})(request) + request = self.factory.post("/v1/register/", data) + response = RegisterUserViewSet.as_view({"post": "create"})(request) response.render() content_data = json.loads(response.content) - return (response, content_data,) + return (response, content_data) def test_okay(self): - email = 'fake@user.com' - password = 'abc!1234' - response, content_data = self.request({ - 'email': email, - 'name': 'Fake', - 'nickname': 'fake', - 'password': password, - }) - self.assertEqual( - response.status_code, - status.HTTP_201_CREATED) + email = "fake@user.com" + password = "abc!1234" + response, content_data = self.request( + {"email": email, "name": "Fake", "nickname": "fake", "password": password} + ) + self.assertEqual(response.status_code, status.HTTP_201_CREATED) user = User.objects.get(email=email) self.assertTrue(user.check_password(password)) def test_invalid_password(self): - response, content_data = self.request({ - 'email': 'fake@user.com', - 'name': 'Fake', - 'nickname': 'fake', - 'password': 'abc', - }) - self.assertEqual( - response.status_code, - status.HTTP_400_BAD_REQUEST) - self.assertIn( - 'password', - content_data.keys()) + response, content_data = self.request( + { + "email": "fake@user.com", + "name": "Fake", + "nickname": "fake", + "password": "abc", + } + ) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + self.assertIn("password", content_data.keys()) def test_unique_nickname(self): - nickname = 'fake' - User.objects.create_user('user1@user.com', nickname) - response, content_data = self.request({ - 'email': 'user2@user.com', - 'name': 'Fake', - 'nickname': nickname, - 'password': 'abc!1234', - }) - self.assertEqual( - response.status_code, - status.HTTP_400_BAD_REQUEST) - self.assertIn( - 'nickname', - content_data.keys()) + nickname = "fake" + User.objects.create_user("user1@user.com", nickname) + response, content_data = self.request( + { + "email": "user2@user.com", + "name": "Fake", + "nickname": nickname, + "password": "abc!1234", + } + ) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + self.assertIn("nickname", content_data.keys()) def test_invalid_nickname_url_conflict(self): - URL_PATHS = [ - 'api', - 'docs', - 'admin', - ] + URL_PATHS = ["api", "docs", "admin"] for url_path in URL_PATHS: - response, content_data = self.request({ - 'email': '{}@fake.com'.format(url_path), - 'name': 'Fake', - 'nickname': url_path, - 'password': 'abc!1234', - }) + response, content_data = self.request( + { + "email": "{}@fake.com".format(url_path), + "name": "Fake", + "nickname": url_path, + "password": "abc!1234", + } + ) - self.assertEqual( - response.status_code, - status.HTTP_400_BAD_REQUEST) - self.assertIn( - 'nickname', - content_data.keys()) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + self.assertIn("nickname", content_data.keys()) class UserUpdateTestCase(TestCase): @@ -105,167 +87,116 @@ def setUp(self): self.user, self.user_token = create_user_and_token() def request(self, user, data, token): - authorization_header = { - 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), - } + authorization_header = {"HTTP_AUTHORIZATION": "Token {}".format(token.key)} request = self.factory.patch( - '/v1/my-profile/', + "/v1/my-profile/", self.factory._encode_data(data, MULTIPART_CONTENT), MULTIPART_CONTENT, - **authorization_header) - response = MyUserProfileViewSet.as_view( - {'patch': 'update'})(request, pk=user.pk, partial=True) + **authorization_header + ) + response = MyUserProfileViewSet.as_view({"patch": "update"})( + request, pk=user.pk, partial=True + ) response.render() content_data = json.loads(response.content) - return (response, content_data,) + return (response, content_data) def test_okay(self): - new_locale = 'Maceió - Alagoas' + new_locale = "Maceió - Alagoas" response, content_data = self.request( - self.user, - { - 'locale': new_locale, - }, - self.user_token) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) - self.assertEqual( - content_data.get('locale'), - new_locale) + self.user, {"locale": new_locale}, self.user_token + ) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(content_data.get("locale"), new_locale) class LoginTestCase(TestCase): def setUp(self): self.factory = RequestFactory() - self.password = 'abcgq!!123' - self.email = 'user@user.com' + self.password = "abcgq!!123" + self.email = "user@user.com" - user = User.objects.create( - email=self.email, - nickname='user', - name='User') + user = User.objects.create(email=self.email, nickname="user", name="User") user.set_password(self.password) - user.save(update_fields=['password']) + user.save(update_fields=["password"]) def request(self, data): - request = self.factory.post( - '/v1/login/', - data) - response = LoginViewSet.as_view( - {'post': 'create'})(request) + request = self.factory.post("/v1/login/", data) + response = LoginViewSet.as_view({"post": "create"})(request) response.render() content_data = json.loads(response.content) - return (response, content_data,) + return (response, content_data) def test_okay(self): - response, content_data = self.request({ - 'username': self.email, - 'password': self.password, - }) - self.assertEqual( - response.status_code, - status.HTTP_201_CREATED) - self.assertIn( - 'token', - content_data.keys()) + response, content_data = self.request( + {"username": self.email, "password": self.password} + ) + self.assertEqual(response.status_code, status.HTTP_201_CREATED) + self.assertIn("token", content_data.keys()) def test_wrong_password(self): - response, content_data = self.request({ - 'username': self.email, - 'password': 'wrong', - }) - self.assertEqual( - response.status_code, - status.HTTP_400_BAD_REQUEST) + response, content_data = self.request( + {"username": self.email, "password": "wrong"} + ) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) class ChangePasswordTestCase(TestCase): def setUp(self): self.factory = RequestFactory() self.user, self.user_token = create_user_and_token() - self.password = '12555q!66' + self.password = "12555q!66" self.user.set_password(self.password) - self.user.save(update_fields=['password']) + self.user.save(update_fields=["password"]) def request(self, data, token): - authorization_header = { - 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), - } - request = self.factory.post( - '/v1/', - data, - **authorization_header) - response = ChangePasswordViewSet.as_view( - {'post': 'update'})(request) + authorization_header = {"HTTP_AUTHORIZATION": "Token {}".format(token.key)} + request = self.factory.post("/v1/", data, **authorization_header) + response = ChangePasswordViewSet.as_view({"post": "update"})(request) response.render() content_data = json.loads(response.content) - return (response, content_data,) + return (response, content_data) def test_okay(self): - new_password = 'kkl8&!qq' + new_password = "kkl8&!qq" response, content_data = self.request( - { - 'current_password': self.password, - 'password': new_password, - }, - self.user_token) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) + {"current_password": self.password, "password": new_password}, + self.user_token, + ) + self.assertEqual(response.status_code, status.HTTP_200_OK) def test_wrong_password(self): response, content_data = self.request( - { - 'current_password': 'wrong_password', - 'password': 'new_password', - }, - self.user_token) - self.assertEqual( - response.status_code, - status.HTTP_400_BAD_REQUEST) - self.assertIn( - 'current_password', - content_data.keys()) + {"current_password": "wrong_password", "password": "new_password"}, + self.user_token, + ) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + self.assertIn("current_password", content_data.keys()) class RequestResetPasswordTestCase(TestCase): def setUp(self): self.factory = RequestFactory() - self.email = 'user@user.com' + self.email = "user@user.com" - User.objects.create( - email=self.email, - nickname='user', - name='User') + User.objects.create(email=self.email, nickname="user", name="User") def request(self, data): - request = self.factory.post( - '/v1/forgot-password/', - data) - response = RequestResetPassword.as_view( - {'post': 'create'})(request) + request = self.factory.post("/v1/forgot-password/", data) + response = RequestResetPassword.as_view({"post": "create"})(request) response.render() content_data = json.loads(response.content) - return (response, content_data,) + return (response, content_data) def test_okay(self): - response, content_data = self.request({ - 'email': self.email, - }) + response, content_data = self.request({"email": self.email}) def test_email_not_found(self): - response, content_data = self.request({ - 'email': 'nouser@fake.com', - }) - self.assertEqual( - response.status_code, - status.HTTP_400_BAD_REQUEST) - self.assertIn( - 'email', - content_data.keys()) + response, content_data = self.request({"email": "nouser@fake.com"}) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + self.assertIn("email", content_data.keys()) class ResetPasswordTestCase(TestCase): @@ -273,48 +204,33 @@ def setUp(self): self.factory = RequestFactory() self.user = User.objects.create( - email='user@user.com', - nickname='user', - name='User') + email="user@user.com", nickname="user", name="User" + ) self.reset_password_token = self.user.make_password_reset_token() def request(self, nickname, data): - request = self.factory.post( - '/v1/reset-password/{}/'.format(nickname), - data) - response = ResetPassword.as_view( - {'post': 'update'})(request, nickname=nickname) + request = self.factory.post("/v1/reset-password/{}/".format(nickname), data) + response = ResetPassword.as_view({"post": "update"})(request, nickname=nickname) response.render() content_data = json.loads(response.content) - return (response, content_data,) + return (response, content_data) def test_okay(self): - new_password = 'valid12!' + new_password = "valid12!" response, content_data = self.request( self.user.nickname, - { - 'token': self.reset_password_token, - 'password': new_password, - }) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) + {"token": self.reset_password_token, "password": new_password}, + ) + self.assertEqual(response.status_code, status.HTTP_200_OK) self.user = User.objects.get(pk=self.user.pk) self.assertTrue(self.user.check_password(new_password)) def test_invalid_token(self): response, content_data = self.request( - self.user.nickname, - { - 'token': '112233', - 'password': 'valid12!', - }) - self.assertEqual( - response.status_code, - status.HTTP_400_BAD_REQUEST) - self.assertIn( - 'token', - content_data.keys()) + self.user.nickname, {"token": "112233", "password": "valid12!"} + ) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + self.assertIn("token", content_data.keys()) class MyUserProfileTestCase(TestCase): @@ -323,23 +239,14 @@ def setUp(self): self.user, self.user_token = create_user_and_token() def request(self, token): - authorization_header = { - 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), - } - request = self.factory.get( - '/v1/my-profile/', - **authorization_header) - response = MyUserProfileViewSet.as_view( - {'get': 'retrieve'})(request) + authorization_header = {"HTTP_AUTHORIZATION": "Token {}".format(token.key)} + request = self.factory.get("/v1/my-profile/", **authorization_header) + response = MyUserProfileViewSet.as_view({"get": "retrieve"})(request) response.render() content_data = json.loads(response.content) - return (response, content_data,) + return (response, content_data) def test_okay(self): response, content_data = self.request(self.user_token) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) - self.assertEqual( - content_data.get('nickname'), - self.user.nickname) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(content_data.get("nickname"), self.user.nickname) diff --git a/bothub/api/v1/tests/utils.py b/bothub/api/v1/tests/utils.py index 7fb5780b..7ede7eb6 100644 --- a/bothub/api/v1/tests/utils.py +++ b/bothub/api/v1/tests/utils.py @@ -3,9 +3,7 @@ from bothub.authentication.models import User -def create_user_and_token(nickname='fake'): - user = User.objects.create_user( - '{}@user.com'.format(nickname), - nickname) +def create_user_and_token(nickname="fake"): + user = User.objects.create_user("{}@user.com".format(nickname), nickname) token, create = Token.objects.get_or_create(user=user) - return (user, token,) + return (user, token) diff --git a/bothub/api/v1/validators.py b/bothub/api/v1/validators.py index 6b96c3b8..eabfa10d 100644 --- a/bothub/api/v1/validators.py +++ b/bothub/api/v1/validators.py @@ -8,102 +8,101 @@ class CanContributeInRepositoryValidator(object): def __call__(self, value): - user_authorization = value.get_user_authorization( - self.request.user) + user_authorization = value.get_user_authorization(self.request.user) if not user_authorization.can_contribute: - raise PermissionDenied( - _('You can\'t contribute in this repository')) + raise PermissionDenied(_("You can't contribute in this repository")) def set_context(self, serializer): - self.request = serializer.context.get('request') + self.request = serializer.context.get("request") class CanContributeInRepositoryExampleValidator(object): def __call__(self, value): repository = value.repository_update.repository - user_authorization = repository.get_user_authorization( - self.request.user) + user_authorization = repository.get_user_authorization(self.request.user) if not user_authorization.can_contribute: - raise PermissionDenied( - _('You can\'t contribute in this repository')) + raise PermissionDenied(_("You can't contribute in this repository")) def set_context(self, serializer): - self.request = serializer.context.get('request') + self.request = serializer.context.get("request") class CanContributeInRepositoryTranslatedExampleValidator(object): def __call__(self, value): repository = value.original_example.repository_update.repository - user_authorization = repository.get_user_authorization( - self.request.user) + user_authorization = repository.get_user_authorization(self.request.user) if not user_authorization.can_contribute: - raise PermissionDenied( - _('You can\'t contribute in this repository')) + raise PermissionDenied(_("You can't contribute in this repository")) def set_context(self, serializer): - self.request = serializer.context.get('request') + self.request = serializer.context.get("request") class TranslatedExampleEntitiesValidator(object): def __call__(self, attrs): - original_example = attrs.get('original_example') - entities_list = list(map(lambda x: dict(x), attrs.get('entities'))) - original_entities_list = list(map( - lambda x: x.to_dict, - original_example.entities.all())) + original_example = attrs.get("original_example") + entities_list = list(map(lambda x: dict(x), attrs.get("entities"))) + original_entities_list = list( + map(lambda x: x.to_dict, original_example.entities.all()) + ) entities_valid = RepositoryTranslatedExample.same_entities_validator( - entities_list, - original_entities_list) + entities_list, original_entities_list + ) if not entities_valid: - raise ValidationError({'entities': _( - 'Entities need to match from the original content. ' + - 'Entities: {0}. Original entities: {1}.').format( - RepositoryTranslatedExample.count_entities( - entities_list, - to_str=True), - RepositoryTranslatedExample.count_entities( - original_entities_list, - to_str=True), - )}) + raise ValidationError( + { + "entities": _( + "Entities need to match from the original content. " + + "Entities: {0}. Original entities: {1}." + ).format( + RepositoryTranslatedExample.count_entities( + entities_list, to_str=True + ), + RepositoryTranslatedExample.count_entities( + original_entities_list, to_str=True + ), + ) + } + ) class TranslatedExampleLanguageValidator(object): def __call__(self, attrs): - original_example = attrs.get('original_example') - language = attrs.get('language') + original_example = attrs.get("original_example") + language = attrs.get("language") if original_example.repository_update.language == language: - raise ValidationError({'language': _( - 'Can\'t translate to the same language')}) + raise ValidationError( + {"language": _("Can't translate to the same language")} + ) class ExampleWithIntentOrEntityValidator(object): def __call__(self, attrs): - intent = attrs.get('intent') - entities = attrs.get('entities') + intent = attrs.get("intent") + entities = attrs.get("entities") if not intent and not entities: - raise ValidationError(_('Define a intent or one entity')) + raise ValidationError(_("Define a intent or one entity")) class IntentAndSentenceNotExistsValidator(object): def __call__(self, attrs): - repository = attrs.get('repository') - intent = attrs.get('intent') - sentence = attrs.get('text') + repository = attrs.get("repository") + intent = attrs.get("intent") + sentence = attrs.get("text") if RepositoryExample.objects.filter( - text=sentence, - intent=intent, - repository_update__repository=repository + text=sentence, intent=intent, repository_update__repository=repository ).count(): - raise ValidationError(_('Intention and Sentence already exists')) + raise ValidationError(_("Intention and Sentence already exists")) class EntityNotEqualLabelValidator(object): def __call__(self, attrs): - entity = attrs.get('entity') - label = attrs.get('label') + entity = attrs.get("entity") + label = attrs.get("label") if entity == label: - raise ValidationError({'label': _( - 'Label name can\'t be equal to entity name')}) + raise ValidationError( + {"label": _("Label name can't be equal to entity name")} + ) diff --git a/bothub/api/v1/views.py b/bothub/api/v1/views.py index 04c38012..8718b9eb 100644 --- a/bothub/api/v1/views.py +++ b/bothub/api/v1/views.py @@ -61,8 +61,8 @@ # Permisions READ_METHODS = permissions.SAFE_METHODS -WRITE_METHODS = ['POST', 'PUT', 'PATCH'] -ADMIN_METHODS = ['DELETE'] +WRITE_METHODS = ["POST", "PUT", "PATCH"] +ADMIN_METHODS = ["DELETE"] class RepositoryPermission(permissions.BasePermission): @@ -79,8 +79,9 @@ def has_object_permission(self, request, view, obj): class RepositoryExamplePermission(permissions.BasePermission): def has_object_permission(self, request, view, obj): - authorization = obj.repository_update.repository \ - .get_user_authorization(request.user) + authorization = obj.repository_update.repository.get_user_authorization( + request.user + ) if request.method in READ_METHODS: return authorization.can_read return authorization.can_contribute @@ -127,34 +128,36 @@ def has_object_permission(self, request, view, obj): # Filters + class ExamplesFilter(filters.FilterSet): class Meta: model = RepositoryExample - fields = [ - 'text', - 'language', - ] + fields = ["text", "language"] repository_uuid = filters.CharFilter( - field_name='repository_uuid', - method='filter_repository_uuid', + field_name="repository_uuid", + method="filter_repository_uuid", required=True, - help_text=_('Repository\'s UUID')) + help_text=_("Repository's UUID"), + ) language = filters.CharFilter( - field_name='language', - method='filter_language', - help_text='Filter by language, default is repository base language') + field_name="language", + method="filter_language", + help_text="Filter by language, default is repository base language", + ) has_translation = filters.BooleanFilter( - field_name='has_translation', - method='filter_has_translation', - help_text=_('Filter for examples with or without translation')) + field_name="has_translation", + method="filter_has_translation", + help_text=_("Filter for examples with or without translation"), + ) has_not_translation_to = filters.CharFilter( - field_name='has_not_translation_to', - method='filter_has_not_translation_to') + field_name="has_not_translation_to", method="filter_has_not_translation_to" + ) order_by_translation = filters.CharFilter( - field_name='order_by_translation', - method='filter_order_by_translation', - help_text=_('Order examples with translation by language')) + field_name="order_by_translation", + method="filter_order_by_translation", + help_text=_("Order examples with translation by language"), + ) def filter_repository_uuid(self, queryset, name, value): request = self.request @@ -165,50 +168,46 @@ def filter_repository_uuid(self, queryset, name, value): raise PermissionDenied() return repository.examples(queryset=queryset) except Repository.DoesNotExist: - raise NotFound( - _('Repository {} does not exist').format(value)) + raise NotFound(_("Repository {} does not exist").format(value)) except DjangoValidationError: - raise NotFound(_('Invalid repository_uuid')) + raise NotFound(_("Invalid repository_uuid")) def filter_language(self, queryset, name, value): return queryset.filter(repository_update__language=value) def filter_has_translation(self, queryset, name, value): - annotated_queryset = queryset.annotate( - translation_count=Count('translations')) + annotated_queryset = queryset.annotate(translation_count=Count("translations")) if value: - return annotated_queryset.filter( - translation_count__gt=0) + return annotated_queryset.filter(translation_count__gt=0) else: - return annotated_queryset.filter( - translation_count=0) + return annotated_queryset.filter(translation_count=0) def filter_has_not_translation_to(self, queryset, name, value): annotated_queryset = queryset.annotate( translation_count=Count( - 'translations', - filter=Q(translations__language=value))) + "translations", filter=Q(translations__language=value) + ) + ) return annotated_queryset.filter(translation_count=0) def filter_order_by_translation(self, queryset, name, value): - inverted = value[0] == '-' + inverted = value[0] == "-" language = value[1:] if inverted else value result_queryset = queryset.annotate( translation_count=Count( - 'translations', - filter=Q(translations__language=language))) + "translations", filter=Q(translations__language=language) + ) + ) result_queryset = result_queryset.order_by( - '-translation_count' if inverted else 'translation_count') + "-translation_count" if inverted else "translation_count" + ) return result_queryset class RepositoriesFilter(filters.FilterSet): class Meta: model = Repository - fields = [ - 'name', - 'categories', - ] + fields = ["name", "categories"] class TranslationsFilter(filters.FilterSet): @@ -217,18 +216,21 @@ class Meta: fields = [] repository_uuid = filters.CharFilter( - field_name='repository_uuid', - method='filter_repository_uuid', + field_name="repository_uuid", + method="filter_repository_uuid", required=True, - help_text=_('Repository\'s UUID')) + help_text=_("Repository's UUID"), + ) from_language = filters.CharFilter( - field_name='language', - method='filter_from_language', - help_text='Filter by original language') + field_name="language", + method="filter_from_language", + help_text="Filter by original language", + ) to_language = filters.CharFilter( - field_name='language', - method='filter_to_language', - help_text='Filter by translated language') + field_name="language", + method="filter_to_language", + help_text="Filter by translated language", + ) def filter_repository_uuid(self, queryset, name, value): request = self.request @@ -238,16 +240,15 @@ def filter_repository_uuid(self, queryset, name, value): if not authorization.can_read: raise PermissionDenied() return RepositoryTranslatedExample.objects.filter( - original_example__repository_update__repository=repository) + original_example__repository_update__repository=repository + ) except Repository.DoesNotExist: - raise NotFound( - _('Repository {} does not exist').format(value)) + raise NotFound(_("Repository {} does not exist").format(value)) except DjangoValidationError: - raise NotFound(_('Invalid repository_uuid')) + raise NotFound(_("Invalid repository_uuid")) def filter_from_language(self, queryset, name, value): - return queryset.filter( - original_example__repository_update__language=value) + return queryset.filter(original_example__repository_update__language=value) def filter_to_language(self, queryset, name, value): return queryset.filter(language=value) @@ -256,12 +257,13 @@ def filter_to_language(self, queryset, name, value): class RepositoryAuthorizationFilter(filters.FilterSet): class Meta: model = RepositoryAuthorization - fields = ['repository'] + fields = ["repository"] repository = filters.CharFilter( - field_name='repository', - method='filter_repository_uuid', - help_text=_('Repository\'s UUID')) + field_name="repository", + method="filter_repository_uuid", + help_text=_("Repository's UUID"), + ) def filter_repository_uuid(self, queryset, name, value): request = self.request @@ -272,22 +274,22 @@ def filter_repository_uuid(self, queryset, name, value): raise PermissionDenied() return queryset.filter(repository=repository) except Repository.DoesNotExist: - raise NotFound( - _('Repository {} does not exist').format(value)) + raise NotFound(_("Repository {} does not exist").format(value)) except DjangoValidationError: - raise NotFound(_('Invalid repository UUID')) + raise NotFound(_("Invalid repository UUID")) class RepositoryAuthorizationRequestsFilter(filters.FilterSet): class Meta: model = RequestRepositoryAuthorization - fields = ['repository_uuid'] + fields = ["repository_uuid"] repository_uuid = filters.CharFilter( - field_name='repository_uuid', + field_name="repository_uuid", required=True, - method='filter_repository_uuid', - help_text=_('Repository\'s UUID')) + method="filter_repository_uuid", + help_text=_("Repository's UUID"), + ) def filter_repository_uuid(self, queryset, name, value): request = self.request @@ -298,25 +300,22 @@ def filter_repository_uuid(self, queryset, name, value): raise PermissionDenied() return queryset.filter(repository=repository) except Repository.DoesNotExist: - raise NotFound( - _('Repository {} does not exist').format(value)) + raise NotFound(_("Repository {} does not exist").format(value)) except DjangoValidationError: - raise NotFound(_('Invalid repository UUID')) + raise NotFound(_("Invalid repository UUID")) class RepositoryEntitiesFilter(filters.FilterSet): class Meta: model = RepositoryEntity - fields = [ - 'repository_uuid', - 'value', - ] + fields = ["repository_uuid", "value"] repository_uuid = filters.CharFilter( - field_name='repository_uuid', + field_name="repository_uuid", required=True, - method='filter_repository_uuid', - help_text=_('Repository\'s UUID')) + method="filter_repository_uuid", + help_text=_("Repository's UUID"), + ) def filter_repository_uuid(self, queryset, name, value): request = self.request @@ -327,24 +326,22 @@ def filter_repository_uuid(self, queryset, name, value): raise PermissionDenied() return queryset.filter(repository=repository) except Repository.DoesNotExist: - raise NotFound( - _('Repository {} does not exist').format(value)) + raise NotFound(_("Repository {} does not exist").format(value)) except DjangoValidationError: - raise NotFound(_('Invalid repository UUID')) + raise NotFound(_("Invalid repository UUID")) class RepositoryUpdatesFilter(filters.FilterSet): class Meta: model = RepositoryUpdate - fields = [ - 'repository_uuid', - ] + fields = ["repository_uuid"] repository_uuid = filters.CharFilter( - field_name='repository_uuid', + field_name="repository_uuid", required=True, - method='filter_repository_uuid', - help_text=_('Repository\'s UUID')) + method="filter_repository_uuid", + help_text=_("Repository's UUID"), + ) def filter_repository_uuid(self, queryset, name, value): request = self.request @@ -355,14 +352,14 @@ def filter_repository_uuid(self, queryset, name, value): raise PermissionDenied() return queryset.filter(repository=repository) except Repository.DoesNotExist: - raise NotFound( - _('Repository {} does not exist').format(value)) + raise NotFound(_("Repository {} does not exist").format(value)) except DjangoValidationError: - raise NotFound(_('Invalid repository UUID')) + raise NotFound(_("Invalid repository UUID")) # Mixins + class MultipleFieldLookupMixin(object): """ Apply this mixin to any view or viewset to get multiple field filtering @@ -384,18 +381,13 @@ def get_object(self): # ViewSets -@method_decorator( - name='create', - decorator=swagger_auto_schema( - deprecated=True - ) -) -class NewRepositoryViewSet( - mixins.CreateModelMixin, - GenericViewSet): + +@method_decorator(name="create", decorator=swagger_auto_schema(deprecated=True)) +class NewRepositoryViewSet(mixins.CreateModelMixin, GenericViewSet): """ Create a new Repository, add examples and train a bot. """ + queryset = Repository.objects serializer_class = NewRepositorySerializer permission_classes = [permissions.IsAuthenticated] @@ -408,40 +400,39 @@ def create(self, request, *args, **kwargs): return Response( RepositorySerializer(instance).data, status=status.HTTP_201_CREATED, - headers=headers) + headers=headers, + ) @method_decorator( - name='list', + name="list", decorator=swagger_auto_schema( manual_parameters=[ openapi.Parameter( - 'nickname', + "nickname", openapi.IN_QUERY, - description='Nickname User to find repositories', - type=openapi.TYPE_STRING - ), + description="Nickname User to find repositories", + type=openapi.TYPE_STRING, + ) ], - deprecated=True - ) + deprecated=True, + ), ) -class SearchRepositoriesViewSet( - mixins.ListModelMixin, - GenericViewSet): +class SearchRepositoriesViewSet(mixins.ListModelMixin, GenericViewSet): """ List all user's repositories """ + queryset = Repository.objects serializer_class = RepositorySerializer - lookup_field = 'nickname' + lookup_field = "nickname" def get_queryset(self, *args, **kwargs): try: - if self.request.query_params.get('nickname', None): + if self.request.query_params.get("nickname", None): return self.queryset.filter( owner__nickname=self.request.query_params.get( - 'nickname', - self.request.user + "nickname", self.request.user ) ) else: @@ -450,36 +441,17 @@ def get_queryset(self, *args, **kwargs): return self.queryset.none() -@method_decorator( - name='retrieve', - decorator=swagger_auto_schema( - deprecated=True - ) -) -@method_decorator( - name='update', - decorator=swagger_auto_schema( - deprecated=True - ) -) -@method_decorator( - name='partial_update', - decorator=swagger_auto_schema( - deprecated=True - ) -) -@method_decorator( - name='destroy', - decorator=swagger_auto_schema( - deprecated=True - ) -) +@method_decorator(name="retrieve", decorator=swagger_auto_schema(deprecated=True)) +@method_decorator(name="update", decorator=swagger_auto_schema(deprecated=True)) +@method_decorator(name="partial_update", decorator=swagger_auto_schema(deprecated=True)) +@method_decorator(name="destroy", decorator=swagger_auto_schema(deprecated=True)) class RepositoryViewSet( - MultipleFieldLookupMixin, - mixins.RetrieveModelMixin, - mixins.UpdateModelMixin, - mixins.DestroyModelMixin, - GenericViewSet): + MultipleFieldLookupMixin, + mixins.RetrieveModelMixin, + mixins.UpdateModelMixin, + mixins.DestroyModelMixin, + GenericViewSet, +): """ Manager repository. @@ -495,44 +467,25 @@ class RepositoryViewSet( delete: Delete your repository. """ + queryset = Repository.objects - lookup_field = 'slug' - lookup_fields = ['owner__nickname', 'slug'] + lookup_field = "slug" + lookup_fields = ["owner__nickname", "slug"] serializer_class = RepositorySerializer edit_serializer_class = EditRepositorySerializer - permission_classes = [ - RepositoryPermission, - ] + permission_classes = [RepositoryPermission] - @method_decorator( - name='list', - decorator=swagger_auto_schema( - deprecated=True - ) - ) - @action( - detail=True, - methods=['GET'], - url_name='repository-languages-status') + @method_decorator(name="list", decorator=swagger_auto_schema(deprecated=True)) + @action(detail=True, methods=["GET"], url_name="repository-languages-status") def languagesstatus(self, request, **kwargs): """ Get current language status. """ repository = self.get_object() - return Response({ - 'languages_status': repository.languages_status, - }) - - @method_decorator( - name='list', - decorator=swagger_auto_schema( - deprecated=True, - ) - ) - @action( - detail=True, - methods=['GET'], - url_name='repository-authorization') + return Response({"languages_status": repository.languages_status}) + + @method_decorator(name="list", decorator=swagger_auto_schema(deprecated=True)) + @action(detail=True, methods=["GET"], url_name="repository-authorization") def authorization(self, request, **kwargs): """ Get authorization to use in Bothub Natural Language Processing service. @@ -544,16 +497,8 @@ def authorization(self, request, **kwargs): serializer = RepositoryAuthorizationSerializer(user_authorization) return Response(serializer.data) - @method_decorator( - name='list', - decorator=swagger_auto_schema( - deprecated=True, - ) - ) - @action( - detail=True, - methods=['GET'], - url_name='repository-train') + @method_decorator(name="list", decorator=swagger_auto_schema(deprecated=True)) + @action(detail=True, methods=["GET"], url_name="repository-train") def train(self, request, **kwargs): """ Train current update using Bothub NLP service @@ -562,34 +507,28 @@ def train(self, request, **kwargs): user_authorization = repository.get_user_authorization(request.user) if not user_authorization.can_write: raise PermissionDenied() - request = repository.request_nlp_train( # pragma: no cover - user_authorization) + request = repository.request_nlp_train(user_authorization) # pragma: no cover if request.status_code != status.HTTP_200_OK: # pragma: no cover raise APIException( # pragma: no cover - {'status_code': request.status_code}, - code=request.status_code) + {"status_code": request.status_code}, code=request.status_code + ) return Response(request.json()) # pragma: no cover - @method_decorator( - name='list', - decorator=swagger_auto_schema( - deprecated=True - ) - ) + @method_decorator(name="list", decorator=swagger_auto_schema(deprecated=True)) @action( detail=True, - methods=['POST'], - url_name='repository-analyze', - permission_classes=[]) + methods=["POST"], + url_name="repository-analyze", + permission_classes=[], + ) def analyze(self, request, **kwargs): repository = self.get_object() user_authorization = repository.get_user_authorization(request.user) - serializer = AnalyzeTextSerializer( - data=request.data) # pragma: no cover + serializer = AnalyzeTextSerializer(data=request.data) # pragma: no cover serializer.is_valid(raise_exception=True) # pragma: no cover request = repository.request_nlp_analyze( - user_authorization, - serializer.data) # pragma: no cover + user_authorization, serializer.data + ) # pragma: no cover if request.status_code == status.HTTP_200_OK: # pragma: no cover return Response(request.json()) # pragma: no cover @@ -602,22 +541,16 @@ def analyze(self, request, **kwargs): if not response: # pragma: no cover raise APIException( # pragma: no cover - detail=_('Something unexpected happened! ' + \ - 'We couldn\'t analyze your text.')) - error = response.get('error') # pragma: no cover - message = error.get('message') # pragma: no cover + detail=_( + "Something unexpected happened! " + "We couldn't analyze your text." + ) + ) + error = response.get("error") # pragma: no cover + message = error.get("message") # pragma: no cover raise APIException(detail=message) # pragma: no cover - @method_decorator( - name='create', - decorator=swagger_auto_schema( - deprecated=True, - ) - ) - @action( - detail=True, - methods=['POST'], - url_name='repository-evaluate') + @method_decorator(name="create", decorator=swagger_auto_schema(deprecated=True)) + @action(detail=True, methods=["POST"], url_name="repository-evaluate") def evaluate(self, request, **kwargs): """ Evaluate repository using Bothub NLP service @@ -626,32 +559,34 @@ def evaluate(self, request, **kwargs): user_authorization = repository.get_user_authorization(request.user) if not user_authorization.can_write: raise PermissionDenied() - serializer = EvaluateSerializer( - data=request.data) # pragma: no cover + serializer = EvaluateSerializer(data=request.data) # pragma: no cover serializer.is_valid(raise_exception=True) # pragma: no cover - if not repository.evaluations( - language=request.data.get('language')).count(): + if not repository.evaluations(language=request.data.get("language")).count(): raise APIException( - detail=_('You need to have at least ' + - 'one registered test phrase')) # pragma: no cover + detail=_("You need to have at least " + "one registered test phrase") + ) # pragma: no cover if len(repository.intents) <= 1: raise APIException( - detail=_('You need to have at least ' + - 'two registered intents')) # pragma: no cover + detail=_("You need to have at least " + "two registered intents") + ) # pragma: no cover request = repository.request_nlp_evaluate( # pragma: no cover - user_authorization, serializer.data) + user_authorization, serializer.data + ) if request.status_code != status.HTTP_200_OK: # pragma: no cover raise APIException( # pragma: no cover - {'status_code': request.status_code}, - code=request.status_code) + {"status_code": request.status_code}, code=request.status_code + ) return Response(request.json()) # pragma: no cover def get_serializer_class(self): - if self.request and self.request.method in \ - ['OPTIONS'] + WRITE_METHODS or not self.request: + if ( + self.request + and self.request.method in ["OPTIONS"] + WRITE_METHODS + or not self.request + ): return self.edit_serializer_class return self.serializer_class @@ -661,10 +596,10 @@ def get_action_permissions_classes(self): fn = getattr(self, self.action, None) if not fn: return None - fn_kwargs = getattr(fn, 'kwargs', None) + fn_kwargs = getattr(fn, "kwargs", None) if not fn_kwargs: return None - permission_classes = fn_kwargs.get('permission_classes') + permission_classes = fn_kwargs.get("permission_classes") if not permission_classes: return None return permission_classes @@ -672,58 +607,31 @@ def get_action_permissions_classes(self): def get_permissions(self): action_permissions_classes = self.get_action_permissions_classes() if action_permissions_classes: - return [permission() - for permission - in action_permissions_classes] + return [permission() for permission in action_permissions_classes] return super().get_permissions() -@method_decorator( - name='create', - decorator=swagger_auto_schema( - deprecated=True, - ) -) -class NewRepositoryExampleViewSet( - mixins.CreateModelMixin, - GenericViewSet): +@method_decorator(name="create", decorator=swagger_auto_schema(deprecated=True)) +class NewRepositoryExampleViewSet(mixins.CreateModelMixin, GenericViewSet): """ Create new repository example. """ + queryset = RepositoryExample.objects serializer_class = NewRepositoryExampleSerializer permission_classes = [permissions.IsAuthenticated] -@method_decorator( - name='retrieve', - decorator=swagger_auto_schema( - deprecated=True, - ) -) -@method_decorator( - name='destroy', - decorator=swagger_auto_schema( - deprecated=True, - ) -) -@method_decorator( - name='update', - decorator=swagger_auto_schema( - deprecated=True, - ) -) -@method_decorator( - name='partial_update', - decorator=swagger_auto_schema( - deprecated=True, - ) -) +@method_decorator(name="retrieve", decorator=swagger_auto_schema(deprecated=True)) +@method_decorator(name="destroy", decorator=swagger_auto_schema(deprecated=True)) +@method_decorator(name="update", decorator=swagger_auto_schema(deprecated=True)) +@method_decorator(name="partial_update", decorator=swagger_auto_schema(deprecated=True)) class RepositoryExampleViewSet( - mixins.RetrieveModelMixin, - mixins.DestroyModelMixin, - mixins.UpdateModelMixin, - GenericViewSet): + mixins.RetrieveModelMixin, + mixins.DestroyModelMixin, + mixins.UpdateModelMixin, + GenericViewSet, +): """ Manager repository example. @@ -737,64 +645,38 @@ class RepositoryExampleViewSet( Update repository example. """ + queryset = RepositoryExample.objects serializer_class = RepositoryExampleSerializer - permission_classes = [ - RepositoryExamplePermission, - ] + permission_classes = [RepositoryExamplePermission] def perform_destroy(self, obj): if obj.deleted_in: - raise APIException(_('Example already deleted')) + raise APIException(_("Example already deleted")) obj.delete() -@method_decorator( - name='create', - decorator=swagger_auto_schema( - deprecated=True, - ) -) -class NewRepositoryTranslatedExampleViewSet( - mixins.CreateModelMixin, - GenericViewSet): +@method_decorator(name="create", decorator=swagger_auto_schema(deprecated=True)) +class NewRepositoryTranslatedExampleViewSet(mixins.CreateModelMixin, GenericViewSet): """ Translate example """ + queryset = RepositoryTranslatedExample.objects serializer_class = NewRepositoryTranslatedExampleSerializer permission_classes = [permissions.IsAuthenticated] -@method_decorator( - name='retrieve', - decorator=swagger_auto_schema( - deprecated=True, - ) -) -@method_decorator( - name='update', - decorator=swagger_auto_schema( - deprecated=True, - ) -) -@method_decorator( - name='partial_update', - decorator=swagger_auto_schema( - deprecated=True, - ) -) -@method_decorator( - name='destroy', - decorator=swagger_auto_schema( - deprecated=True, - ) -) +@method_decorator(name="retrieve", decorator=swagger_auto_schema(deprecated=True)) +@method_decorator(name="update", decorator=swagger_auto_schema(deprecated=True)) +@method_decorator(name="partial_update", decorator=swagger_auto_schema(deprecated=True)) +@method_decorator(name="destroy", decorator=swagger_auto_schema(deprecated=True)) class RepositoryTranslatedExampleViewSet( - mixins.RetrieveModelMixin, - mixins.UpdateModelMixin, - mixins.DestroyModelMixin, - GenericViewSet): + mixins.RetrieveModelMixin, + mixins.UpdateModelMixin, + mixins.DestroyModelMixin, + GenericViewSet, +): """ Manager example translation. @@ -810,6 +692,7 @@ class RepositoryTranslatedExampleViewSet( delete: Delete example translation. """ + queryset = RepositoryTranslatedExample.objects serializer_class = RepositoryTranslatedExampleSerializer permission_classes = [ @@ -818,51 +701,30 @@ class RepositoryTranslatedExampleViewSet( ] -@method_decorator( - name='list', - decorator=swagger_auto_schema( - deprecated=True, - ) -) -class RepositoryExamplesViewSet( - mixins.ListModelMixin, - GenericViewSet): +@method_decorator(name="list", decorator=swagger_auto_schema(deprecated=True)) +class RepositoryExamplesViewSet(mixins.ListModelMixin, GenericViewSet): queryset = RepositoryExample.objects serializer_class = RepositoryExampleSerializer filter_class = ExamplesFilter - filter_backends = [ - DjangoFilterBackend, - OrderingFilter, - ] - ordering_fields = [ - 'created_at', - ] - permission_classes = [ - RepositoryExamplePermission, - ] + filter_backends = [DjangoFilterBackend, OrderingFilter] + ordering_fields = ["created_at"] + permission_classes = [RepositoryExamplePermission] -@method_decorator( - name='create', - decorator=swagger_auto_schema( - deprecated=True - ), -) -class RegisterUserViewSet( - mixins.CreateModelMixin, - GenericViewSet): +@method_decorator(name="create", decorator=swagger_auto_schema(deprecated=True)) +class RegisterUserViewSet(mixins.CreateModelMixin, GenericViewSet): """ Register new user """ + queryset = User.objects serializer_class = RegisterUserSerializer @method_decorator( - name='create', + name="create", decorator=swagger_auto_schema( - responses={201: '{"token":"TOKEN"}'}, - deprecated=True + responses={201: '{"token":"TOKEN"}'}, deprecated=True ), ) class LoginViewSet(GenericViewSet): @@ -876,34 +738,27 @@ class LoginViewSet(GenericViewSet): def create(self, request, *args, **kwargs): serializer = self.serializer_class( - data=request.data, - context={'request': request}) + data=request.data, context={"request": request} + ) serializer.is_valid(raise_exception=True) - user = serializer.validated_data['user'] + user = serializer.validated_data["user"] token, created = Token.objects.get_or_create(user=user) return Response( - { - 'token': token.key, - }, - status.HTTP_201_CREATED if created else status.HTTP_200_OK) + {"token": token.key}, + status.HTTP_201_CREATED if created else status.HTTP_200_OK, + ) -@method_decorator( - name='update', - decorator=swagger_auto_schema( - deprecated=True - ), -) +@method_decorator(name="update", decorator=swagger_auto_schema(deprecated=True)) class ChangePasswordViewSet(GenericViewSet): """ Change current user password. """ + serializer_class = ChangePasswordSerializer queryset = User.objects lookup_field = None - permission_classes = [ - permissions.IsAuthenticated, - ] + permission_classes = [permissions.IsAuthenticated] def get_object(self, *args, **kwargs): request = self.request @@ -919,30 +774,24 @@ def update(self, request, *args, **kwargs): serializer = self.get_serializer(data=request.data) if serializer.is_valid(): - self.object.set_password(serializer.data.get('password')) + self.object.set_password(serializer.data.get("password")) self.object.save() return Response({}, status=status.HTTP_200_OK) - return Response( - serializer.errors, - status=status.HTTP_400_BAD_REQUEST) + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) -@method_decorator( - name='create', - decorator=swagger_auto_schema( - deprecated=True - ), -) +@method_decorator(name="create", decorator=swagger_auto_schema(deprecated=True)) class RequestResetPassword(GenericViewSet): """ Request reset password """ + serializer_class = RequestResetPasswordSerializer queryset = User.objects def get_object(self): - return self.queryset.get(email=self.request.data.get('email')) + return self.queryset.get(email=self.request.data.get("email")) def create(self, request, *args, **kwargs): serializer = self.get_serializer(data=request.data) @@ -950,59 +799,35 @@ def create(self, request, *args, **kwargs): self.object = self.get_object() self.object.send_reset_password_email() return Response({}) - return Response( - serializer.errors, - status=status.HTTP_400_BAD_REQUEST) + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) -@method_decorator( - name='update', - decorator=swagger_auto_schema( - deprecated=True - ), -) +@method_decorator(name="update", decorator=swagger_auto_schema(deprecated=True)) class ResetPassword(GenericViewSet): """ Reset password """ + serializer_class = ResetPasswordSerializer queryset = User.objects - lookup_field = 'nickname' + lookup_field = "nickname" def update(self, request, *args, **kwargs): self.object = self.get_object() serializer = self.get_serializer(data=request.data) if serializer.is_valid(): - self.object.set_password(serializer.data.get('password')) + self.object.set_password(serializer.data.get("password")) self.object.save() return Response({}) - return Response( - serializer.errors, - status=status.HTTP_400_BAD_REQUEST) + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) -@method_decorator( - name='update', - decorator=swagger_auto_schema( - deprecated=True - ), -) -@method_decorator( - name='retrieve', - decorator=swagger_auto_schema( - deprecated=True - ), -) -@method_decorator( - name='partial_update', - decorator=swagger_auto_schema( - deprecated=True - ), -) +@method_decorator(name="update", decorator=swagger_auto_schema(deprecated=True)) +@method_decorator(name="retrieve", decorator=swagger_auto_schema(deprecated=True)) +@method_decorator(name="partial_update", decorator=swagger_auto_schema(deprecated=True)) class MyUserProfileViewSet( - mixins.RetrieveModelMixin, - mixins.UpdateModelMixin, - GenericViewSet): + mixins.RetrieveModelMixin, mixins.UpdateModelMixin, GenericViewSet +): """ Manager current user profile. @@ -1015,12 +840,11 @@ class MyUserProfileViewSet( partial_update: Update, partially, current user profile. """ + serializer_class = UserSerializer queryset = User.objects lookup_field = None - permission_classes = [ - permissions.IsAuthenticated, - ] + permission_classes = [permissions.IsAuthenticated] def get_object(self, *args, **kwargs): request = self.request @@ -1032,162 +856,120 @@ def get_object(self, *args, **kwargs): return user -@method_decorator( - name='retrieve', - decorator=swagger_auto_schema( - deprecated=True - ), -) -class UserProfileViewSet( - mixins.RetrieveModelMixin, - GenericViewSet): +@method_decorator(name="retrieve", decorator=swagger_auto_schema(deprecated=True)) +class UserProfileViewSet(mixins.RetrieveModelMixin, GenericViewSet): """ Get user profile """ + serializer_class = UserSerializer queryset = User.objects - lookup_field = 'nickname' + lookup_field = "nickname" -@method_decorator( - name='list', - decorator=swagger_auto_schema( - deprecated=True, - ) -) -class Categories( - mixins.ListModelMixin, - GenericViewSet): +@method_decorator(name="list", decorator=swagger_auto_schema(deprecated=True)) +class Categories(mixins.ListModelMixin, GenericViewSet): """ List all categories. """ + serializer_class = RepositoryCategorySerializer queryset = RepositoryCategory.objects.all() pagination_class = None -@method_decorator( - name='list', - decorator=swagger_auto_schema( - deprecated=True, - ) -) -class RepositoriesViewSet( - mixins.ListModelMixin, - GenericViewSet): +@method_decorator(name="list", decorator=swagger_auto_schema(deprecated=True)) +class RepositoriesViewSet(mixins.ListModelMixin, GenericViewSet): """ List all public repositories. """ + serializer_class = RepositorySerializer queryset = Repository.objects.all().publics().order_by_relevance() filter_class = RepositoriesFilter - filter_backends = [ - DjangoFilterBackend, - SearchFilter, - ] - search_fields = [ - '$name', - '^name', - '=name', - ] + filter_backends = [DjangoFilterBackend, SearchFilter] + search_fields = ["$name", "^name", "=name"] -@method_decorator( - name='list', - decorator=swagger_auto_schema( - deprecated=True, - ) -) -class TranslationsViewSet( - mixins.ListModelMixin, - GenericViewSet): +@method_decorator(name="list", decorator=swagger_auto_schema(deprecated=True)) +class TranslationsViewSet(mixins.ListModelMixin, GenericViewSet): """ List repository translations. """ + serializer_class = RepositoryTranslatedExampleSerializer queryset = RepositoryTranslatedExample.objects.all() filter_class = TranslationsFilter -@method_decorator( - name='list', - decorator=swagger_auto_schema( - deprecated=True, - ) -) -class RepositoryAuthorizationViewSet( - mixins.ListModelMixin, - GenericViewSet): +@method_decorator(name="list", decorator=swagger_auto_schema(deprecated=True)) +class RepositoryAuthorizationViewSet(mixins.ListModelMixin, GenericViewSet): queryset = RepositoryAuthorization.objects.exclude( - role=RepositoryAuthorization.ROLE_NOT_SETTED) + role=RepositoryAuthorization.ROLE_NOT_SETTED + ) serializer_class = RepositoryAuthorizationSerializer filter_class = RepositoryAuthorizationFilter - permission_classes = [ - IsAuthenticated, - ] + permission_classes = [IsAuthenticated] @method_decorator( - name='update', + name="update", decorator=swagger_auto_schema( manual_parameters=[ openapi.Parameter( - 'repository__uuid', + "repository__uuid", openapi.IN_PATH, - description='Repository UUID', + description="Repository UUID", type=openapi.TYPE_STRING, - required=True + required=True, ), openapi.Parameter( - 'user__nickname', + "user__nickname", openapi.IN_QUERY, - description='Nickname User', + description="Nickname User", type=openapi.TYPE_STRING, - required=True + required=True, ), ], - deprecated=True - ) + deprecated=True, + ), ) @method_decorator( - name='partial_update', + name="partial_update", decorator=swagger_auto_schema( manual_parameters=[ openapi.Parameter( - 'repository__uuid', + "repository__uuid", openapi.IN_PATH, - description='Repository UUID', + description="Repository UUID", type=openapi.TYPE_STRING, - required=True + required=True, ), openapi.Parameter( - 'user__nickname', + "user__nickname", openapi.IN_QUERY, - description='Nickname User', + description="Nickname User", type=openapi.TYPE_STRING, - required=True + required=True, ), ], - deprecated=True - ) + deprecated=True, + ), ) class RepositoryAuthorizationRoleViewSet( - MultipleFieldLookupMixin, - mixins.UpdateModelMixin, - GenericViewSet): + MultipleFieldLookupMixin, mixins.UpdateModelMixin, GenericViewSet +): queryset = RepositoryAuthorization.objects.exclude( - role=RepositoryAuthorization.ROLE_NOT_SETTED) - lookup_field = 'user__nickname' - lookup_fields = ['repository__uuid', 'user__nickname'] + role=RepositoryAuthorization.ROLE_NOT_SETTED + ) + lookup_field = "user__nickname" + lookup_fields = ["repository__uuid", "user__nickname"] serializer_class = RepositoryAuthorizationRoleSerializer - permission_classes = [ - IsAuthenticated, - RepositoryAdminManagerAuthorization, - ] + permission_classes = [IsAuthenticated, RepositoryAdminManagerAuthorization] def get_object(self): - repository_uuid = self.kwargs.get('repository__uuid') - user_nickname = self.kwargs.get('user__nickname') + repository_uuid = self.kwargs.get("repository__uuid") + user_nickname = self.kwargs.get("user__nickname") repository = get_object_or_404(Repository, uuid=repository_uuid) user = get_object_or_404(User, nickname=user_nickname) @@ -1205,111 +987,66 @@ def update(self, *args, **kwargs): return response -@method_decorator( - name='list', - decorator=swagger_auto_schema( - deprecated=True, - ) -) -class SearchUserViewSet( - mixins.ListModelMixin, - GenericViewSet): +@method_decorator(name="list", decorator=swagger_auto_schema(deprecated=True)) +class SearchUserViewSet(mixins.ListModelMixin, GenericViewSet): serializer_class = UserSerializer queryset = User.objects.all() - filter_backends = [ - DjangoFilterBackend, - SearchFilter, - ] + filter_backends = [DjangoFilterBackend, SearchFilter] search_fields = [ - '=name', - '^name', - '$name', - '=nickname', - '^nickname', - '$nickname', - '=email', + "=name", + "^name", + "$name", + "=nickname", + "^nickname", + "$nickname", + "=email", ] pagination_class = None limit = 5 def list(self, request, *args, **kwargs): - queryset = self.filter_queryset(self.get_queryset())[:self.limit] + queryset = self.filter_queryset(self.get_queryset())[: self.limit] serializer = self.get_serializer(queryset, many=True) return Response(serializer.data) -@method_decorator( - name='create', - decorator=swagger_auto_schema( - deprecated=True, - ) -) -class RequestAuthorizationViewSet( - mixins.CreateModelMixin, - GenericViewSet): +@method_decorator(name="create", decorator=swagger_auto_schema(deprecated=True)) +class RequestAuthorizationViewSet(mixins.CreateModelMixin, GenericViewSet): """ Request authorization in the repository """ + serializer_class = NewRequestRepositoryAuthorizationSerializer queryset = RequestRepositoryAuthorization.objects - permission_classes = [ - IsAuthenticated, - ] + permission_classes = [IsAuthenticated] -@method_decorator( - name='list', - decorator=swagger_auto_schema( - deprecated=True, - ) -) -class RepositoryAuthorizationRequestsViewSet( - mixins.ListModelMixin, - GenericViewSet): +@method_decorator(name="list", decorator=swagger_auto_schema(deprecated=True)) +class RepositoryAuthorizationRequestsViewSet(mixins.ListModelMixin, GenericViewSet): """ List of all authorization requests for a repository """ - queryset = RequestRepositoryAuthorization.objects.exclude( - approved_by__isnull=False) + + queryset = RequestRepositoryAuthorization.objects.exclude(approved_by__isnull=False) serializer_class = RequestRepositoryAuthorizationSerializer filter_class = RepositoryAuthorizationRequestsFilter - permission_classes = [ - IsAuthenticated, - ] + permission_classes = [IsAuthenticated] -@method_decorator( - name='update', - decorator=swagger_auto_schema( - deprecated=True, - ) -) -@method_decorator( - name='destroy', - decorator=swagger_auto_schema( - deprecated=True, - ) -) -@method_decorator( - name='partial_update', - decorator=swagger_auto_schema( - deprecated=True, - ) -) +@method_decorator(name="update", decorator=swagger_auto_schema(deprecated=True)) +@method_decorator(name="destroy", decorator=swagger_auto_schema(deprecated=True)) +@method_decorator(name="partial_update", decorator=swagger_auto_schema(deprecated=True)) class ReviewAuthorizationRequestViewSet( - mixins.UpdateModelMixin, - mixins.DestroyModelMixin, - GenericViewSet): + mixins.UpdateModelMixin, mixins.DestroyModelMixin, GenericViewSet +): """ Authorizes or Removes the user who requested authorization from a repository """ + queryset = RequestRepositoryAuthorization.objects serializer_class = ReviewAuthorizationRequestSerializer - permission_classes = [ - IsAuthenticated, - RepositoryAdminManagerAuthorization, - ] + permission_classes = [IsAuthenticated, RepositoryAdminManagerAuthorization] def update(self, *args, **kwargs): try: @@ -1318,38 +1055,19 @@ def update(self, *args, **kwargs): raise ValidationError(e.message) -@method_decorator( - name='list', - decorator=swagger_auto_schema( - deprecated=True, - ) -) -class RepositoryEntitiesViewSet( - mixins.ListModelMixin, - GenericViewSet): +@method_decorator(name="list", decorator=swagger_auto_schema(deprecated=True)) +class RepositoryEntitiesViewSet(mixins.ListModelMixin, GenericViewSet): queryset = RepositoryEntity.objects.all() serializer_class = RepositoryEntitySerializer filter_class = RepositoryEntitiesFilter - permission_classes = [ - IsAuthenticated, - RepositoryEntityHasPermission, - ] + permission_classes = [IsAuthenticated, RepositoryEntityHasPermission] -@method_decorator( - name='list', - decorator=swagger_auto_schema( - deprecated=True, - ) -) -class RepositoryUpdatesViewSet( - mixins.ListModelMixin, - GenericViewSet): +@method_decorator(name="list", decorator=swagger_auto_schema(deprecated=True)) +class RepositoryUpdatesViewSet(mixins.ListModelMixin, GenericViewSet): queryset = RepositoryUpdate.objects.filter( - training_started_at__isnull=False).order_by('-trained_at') + training_started_at__isnull=False + ).order_by("-trained_at") serializer_class = RepositoryUpdateSerializer filter_class = RepositoryUpdatesFilter - permission_classes = [ - IsAuthenticated, - RepositoryUpdateHasPermission, - ] + permission_classes = [IsAuthenticated, RepositoryUpdateHasPermission] diff --git a/bothub/api/v2/__init__.py b/bothub/api/v2/__init__.py index 8f06f102..72b0bccf 100644 --- a/bothub/api/v2/__init__.py +++ b/bothub/api/v2/__init__.py @@ -2,5 +2,5 @@ READ_METHODS = permissions.SAFE_METHODS -WRITE_METHODS = ['POST', 'PUT', 'PATCH'] -ADMIN_METHODS = ['DELETE'] +WRITE_METHODS = ["POST", "PUT", "PATCH"] +ADMIN_METHODS = ["DELETE"] diff --git a/bothub/api/v2/account/serializers.py b/bothub/api/v2/account/serializers.py index 8b458ce6..4e860caa 100644 --- a/bothub/api/v2/account/serializers.py +++ b/bothub/api/v2/account/serializers.py @@ -10,37 +10,21 @@ class LoginSerializer(AuthTokenSerializer, serializers.ModelSerializer): - username = serializers.EmailField( - label=_('Email'), - ) - password = PasswordField( - label=_('Password'), - ) + username = serializers.EmailField(label=_("Email")) + password = PasswordField(label=_("Password")) class Meta: model = User - fields = [ - 'username', - 'password', - ] + fields = ["username", "password"] ref_name = None class RegisterUserSerializer(serializers.ModelSerializer): - password = PasswordField( - write_only=True, - validators=[ - validate_password, - ]) + password = PasswordField(write_only=True, validators=[validate_password]) class Meta: model = User - fields = [ - 'email', - 'name', - 'nickname', - 'password', - ] + fields = ["email", "name", "nickname", "password"] ref_name = None @staticmethod @@ -49,42 +33,27 @@ def validate_password(value): class ChangePasswordSerializer(serializers.ModelSerializer): - current_password = PasswordField( - required=True - ) - password = PasswordField( - required=True, - validators=[ - validate_password, - ] - ) + current_password = PasswordField(required=True) + password = PasswordField(required=True, validators=[validate_password]) class Meta: model = User - fields = [ - 'current_password', - 'password' - ] + fields = ["current_password", "password"] ref_name = None def validate_current_password(self, value): - request = self.context.get('request') + request = self.context.get("request") if not request.user.check_password(value): - raise ValidationError(_('Wrong password')) + raise ValidationError(_("Wrong password")) return value class RequestResetPasswordSerializer(serializers.ModelSerializer): - email = serializers.EmailField( - label=_('Email'), - required=True - ) + email = serializers.EmailField(label=_("Email"), required=True) class Meta: model = User - fields = [ - 'email' - ] + fields = ["email"] ref_name = None def validate_email(self, value): @@ -92,42 +61,29 @@ def validate_email(self, value): User.objects.get(email=value) return value except User.DoesNotExist: - raise ValidationError(_('No user registered with this email')) + raise ValidationError(_("No user registered with this email")) class UserSerializer(serializers.ModelSerializer): class Meta: model = User - fields = [ - 'nickname', - 'name', - 'locale', - ] + fields = ["nickname", "name", "locale"] ref_name = None class ResetPasswordSerializer(serializers.ModelSerializer): - token = serializers.CharField( - label=_('Token'), - style={'show': False} - ) + token = serializers.CharField(label=_("Token"), style={"show": False}) password = PasswordField( - label=_('New Password'), - required=True, - validators=[ - validate_password, - ]) + label=_("New Password"), required=True, validators=[validate_password] + ) class Meta: model = User - fields = [ - 'token', - 'password', - ] + fields = ["token", "password"] ref_name = None def validate_token(self, value): - user = self.context.get('view').get_object() + user = self.context.get("view").get_object() if not user.check_password_reset_token(value): - raise ValidationError(_('Invalid token for this user')) + raise ValidationError(_("Invalid token for this user")) return value diff --git a/bothub/api/v2/account/views.py b/bothub/api/v2/account/views.py index c79c3b18..211a2a3e 100644 --- a/bothub/api/v2/account/views.py +++ b/bothub/api/v2/account/views.py @@ -19,10 +19,7 @@ @method_decorator( - name='create', - decorator=swagger_auto_schema( - responses={201: '{"token":"TOKEN"}'} - ) + name="create", decorator=swagger_auto_schema(responses={201: '{"token":"TOKEN"}'}) ) class LoginViewSet(mixins.CreateModelMixin, GenericViewSet): @@ -32,32 +29,30 @@ class LoginViewSet(mixins.CreateModelMixin, GenericViewSet): queryset = User.objects serializer_class = LoginSerializer - lookup_field = ('username', 'password') + lookup_field = ("username", "password") metadata_class = Metadata def create(self, request, *args, **kwargs): serializer = self.serializer_class( - data=request.data, - context={'request': request}) + data=request.data, context={"request": request} + ) serializer.is_valid(raise_exception=True) - user = serializer.validated_data['user'] + user = serializer.validated_data["user"] token, created = Token.objects.get_or_create(user=user) return Response( - { - 'token': token.key, - }, - status.HTTP_201_CREATED if created else status.HTTP_200_OK) + {"token": token.key}, + status.HTTP_201_CREATED if created else status.HTTP_200_OK, + ) -class RegisterUserViewSet( - mixins.CreateModelMixin, - GenericViewSet): +class RegisterUserViewSet(mixins.CreateModelMixin, GenericViewSet): """ Register new user """ + queryset = User.objects serializer_class = RegisterUserSerializer - lookup_field = ('email', 'name', 'nickname', 'password') + lookup_field = ("email", "name", "nickname", "password") metadata_class = Metadata @@ -65,12 +60,11 @@ class ChangePasswordViewSet(mixins.UpdateModelMixin, GenericViewSet): """ Change current user password. """ + serializer_class = ChangePasswordSerializer queryset = User.objects lookup_field = None - permission_classes = [ - permissions.IsAuthenticated - ] + permission_classes = [permissions.IsAuthenticated] metadata_class = Metadata def get_object(self, *args, **kwargs): @@ -87,27 +81,26 @@ def update(self, request, *args, **kwargs): serializer = self.get_serializer(data=request.data) if serializer.is_valid(): - self.object.set_password(serializer.data.get('password')) + self.object.set_password(serializer.data.get("password")) self.object.save() return Response(status=status.HTTP_200_OK) - return Response( - serializer.errors, - status=status.HTTP_400_BAD_REQUEST) + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) class RequestResetPasswordViewSet(mixins.CreateModelMixin, GenericViewSet): """ Request reset password """ + serializer_class = RequestResetPasswordSerializer queryset = User.objects - lookup_field = ['email'] + lookup_field = ["email"] permission_classes = [permissions.AllowAny] metadata_class = Metadata def get_object(self): - return self.queryset.get(email=self.request.data.get('email')) + return self.queryset.get(email=self.request.data.get("email")) def create(self, request, *args, **kwargs): serializer = self.get_serializer(data=request.data) @@ -115,47 +108,40 @@ def create(self, request, *args, **kwargs): self.object = self.get_object() self.object.send_reset_password_email() return Response(status=status.HTTP_201_CREATED) - return Response( - serializer.errors, - status=status.HTTP_400_BAD_REQUEST) + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) class UserProfileViewSet( - mixins.RetrieveModelMixin, - mixins.UpdateModelMixin, - GenericViewSet): + mixins.RetrieveModelMixin, mixins.UpdateModelMixin, GenericViewSet +): """ Get user profile """ + serializer_class = UserSerializer queryset = User.objects - lookup_field = 'nickname' - permission_classes = [ - permissions.IsAuthenticatedOrReadOnly - ] + lookup_field = "nickname" + permission_classes = [permissions.IsAuthenticatedOrReadOnly] class SearchUserViewSet(mixins.ListModelMixin, GenericViewSet): serializer_class = UserSerializer queryset = User.objects.all() - filter_backends = [ - DjangoFilterBackend, - SearchFilter, - ] + filter_backends = [DjangoFilterBackend, SearchFilter] search_fields = [ - '=name', - '^name', - '$name', - '=nickname', - '^nickname', - '$nickname', - '=email', + "=name", + "^name", + "$name", + "=nickname", + "^nickname", + "$nickname", + "=email", ] pagination_class = None limit = 5 def list(self, request, *args, **kwargs): - queryset = self.filter_queryset(self.get_queryset())[:self.limit] + queryset = self.filter_queryset(self.get_queryset())[: self.limit] serializer = self.get_serializer(queryset, many=True) return Response(serializer.data) @@ -164,17 +150,16 @@ class ResetPasswordViewSet(mixins.UpdateModelMixin, GenericViewSet): """ Reset password """ + serializer_class = ResetPasswordSerializer queryset = User.objects - lookup_field = 'nickname' + lookup_field = "nickname" def update(self, request, *args, **kwargs): self.object = self.get_object() serializer = self.get_serializer(data=request.data) if serializer.is_valid(): - self.object.set_password(serializer.data.get('password')) + self.object.set_password(serializer.data.get("password")) self.object.save() return Response(status=status.HTTP_200_OK) - return Response( - serializer.errors, - status=status.HTTP_400_BAD_REQUEST) + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) diff --git a/bothub/api/v2/evaluate/filters.py b/bothub/api/v2/evaluate/filters.py index e1fa4044..410be30f 100644 --- a/bothub/api/v2/evaluate/filters.py +++ b/bothub/api/v2/evaluate/filters.py @@ -11,38 +11,34 @@ class EvaluatesFilter(filters.FilterSet): - class Meta: model = RepositoryEvaluate - fields = [ - 'text', - 'language', - 'intent', - ] + fields = ["text", "language", "intent"] repository_uuid = filters.CharFilter( - field_name='repository_uuid', - method='filter_repository_uuid', + field_name="repository_uuid", + method="filter_repository_uuid", required=True, - help_text=_('Repository\'s UUID')) + help_text=_("Repository's UUID"), + ) language = filters.CharFilter( - field_name='language', - method='filter_language', - help_text='Filter by language, default is repository base language') + field_name="language", + method="filter_language", + help_text="Filter by language, default is repository base language", + ) label = filters.CharFilter( - field_name='label', - method='filter_label', - help_text=_( - 'Filter evaluations with entities with a specific label.' - ) + field_name="label", + method="filter_label", + help_text=_("Filter evaluations with entities with a specific label."), ) entity = filters.CharFilter( - field_name='entity', - method='filter_entity', - help_text=_('Filter evaluations with an entity.')) + field_name="entity", + method="filter_entity", + help_text=_("Filter evaluations with an entity."), + ) def filter_repository_uuid(self, queryset, name, value): request = self.request @@ -53,16 +49,15 @@ def filter_repository_uuid(self, queryset, name, value): raise PermissionDenied() return repository.evaluations(queryset=queryset) except Repository.DoesNotExist: - raise NotFound( - _('Repository {} does not exist').format(value)) + raise NotFound(_("Repository {} does not exist").format(value)) except DjangoValidationError: - raise NotFound(_('Invalid repository_uuid')) + raise NotFound(_("Invalid repository_uuid")) def filter_language(self, queryset, name, value): return queryset.filter(repository_update__language=value) def filter_label(self, queryset, name, value): - if value == 'other': + if value == "other": return queryset.filter(entities__entity__label__isnull=True) return queryset.filter(entities__entity__label__value=value) @@ -71,16 +66,16 @@ def filter_entity(self, queryset, name, value): class EvaluateResultsFilter(filters.FilterSet): - class Meta: model = RepositoryEvaluateResult fields = [] repository_uuid = filters.CharFilter( - field_name='repository_uuid', - method='filter_repository_uuid', + field_name="repository_uuid", + method="filter_repository_uuid", required=True, - help_text=_('Repository\'s UUID')) + help_text=_("Repository's UUID"), + ) def filter_repository_uuid(self, queryset, name, value): request = self.request @@ -92,29 +87,29 @@ def filter_repository_uuid(self, queryset, name, value): raise PermissionDenied() return repository.evaluations_results(queryset=queryset) except Repository.DoesNotExist: - raise NotFound( - _('Repository {} does not exist').format(value)) + raise NotFound(_("Repository {} does not exist").format(value)) except DjangoValidationError: - raise NotFound(_('Invalid repository_uuid')) + raise NotFound(_("Invalid repository_uuid")) class EvaluateResultFilter(filters.FilterSet): - class Meta: model = RepositoryEvaluateResult fields = [] text = filters.CharFilter( - field_name='text', - method='filter_evaluate_text', + field_name="text", + method="filter_evaluate_text", required=False, - help_text=_('Evaluate Text')) + help_text=_("Evaluate Text"), + ) repository_uuid = filters.CharFilter( - field_name='repository_uuid', - method='filter_repository_uuid', + field_name="repository_uuid", + method="filter_repository_uuid", required=True, - help_text=_('Repository\'s UUID')) + help_text=_("Repository's UUID"), + ) def filter_evaluate_text(self, queryset, name, value): return queryset.filter(log__icontains=value) @@ -129,7 +124,6 @@ def filter_repository_uuid(self, queryset, name, value): raise PermissionDenied() return repository.evaluations_results(queryset=queryset) except Repository.DoesNotExist: - raise NotFound( - _('Repository {} does not exist').format(value)) + raise NotFound(_("Repository {} does not exist").format(value)) except DjangoValidationError: - raise NotFound(_('Invalid repository_uuid')) + raise NotFound(_("Invalid repository_uuid")) diff --git a/bothub/api/v2/evaluate/permissions.py b/bothub/api/v2/evaluate/permissions.py index a2d720a5..b06f4a35 100644 --- a/bothub/api/v2/evaluate/permissions.py +++ b/bothub/api/v2/evaluate/permissions.py @@ -6,16 +6,12 @@ class RepositoryEvaluatePermission(permissions.BasePermission): - def has_permission(self, request, view): try: - repository = Repository.objects.get( - uuid=request.GET.get('repository_uuid') - ) + repository = Repository.objects.get(uuid=request.GET.get("repository_uuid")) authorization = repository.get_user_authorization(request.user) - if request.method in READ_METHODS and \ - not request.user.is_authenticated: + if request.method in READ_METHODS and not request.user.is_authenticated: return authorization.can_read if request.user.is_authenticated: @@ -30,12 +26,9 @@ def has_permission(self, request, view): class RepositoryEvaluateResultPermission(permissions.BasePermission): - def has_permission(self, request, view): try: - repository = Repository.objects.get( - uuid=request.GET.get('repository_uuid') - ) + repository = Repository.objects.get(uuid=request.GET.get("repository_uuid")) authorization = repository.get_user_authorization(request.user) if request.method in READ_METHODS: diff --git a/bothub/api/v2/evaluate/serializers.py b/bothub/api/v2/evaluate/serializers.py index 080d0371..8ecd7120 100644 --- a/bothub/api/v2/evaluate/serializers.py +++ b/bothub/api/v2/evaluate/serializers.py @@ -20,53 +20,36 @@ class RepositoryEvaluateEntitySerializer(serializers.ModelSerializer): - class Meta: model = RepositoryEvaluateEntity - fields = [ - 'entity', - 'start', - 'end', - ] + fields = ["entity", "start", "end"] ref_name = None entity = EntityValueField() class RepositoryEvaluateSerializer(serializers.ModelSerializer): - class Meta: model = RepositoryEvaluate fields = [ - 'id', - 'repository', - 'text', - 'language', - 'intent', - 'entities', - 'created_at', - ] - read_only_fields = [ - 'deleted_in', - 'created_at', + "id", + "repository", + "text", + "language", + "intent", + "entities", + "created_at", ] + read_only_fields = ["deleted_in", "created_at"] ref_name = None - entities = RepositoryEvaluateEntitySerializer( - many=True, - required=False, - ) + entities = RepositoryEvaluateEntitySerializer(many=True, required=False) repository = serializers.PrimaryKeyRelatedField( - queryset=Repository.objects, - write_only=True, - required=True, + queryset=Repository.objects, write_only=True, required=True ) - language = serializers.ChoiceField( - LANGUAGE_CHOICES, - label=_('Language') - ) + language = serializers.ChoiceField(LANGUAGE_CHOICES, label=_("Language")) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) @@ -74,47 +57,43 @@ def __init__(self, *args, **kwargs): self.validators.append(ThereIsIntentValidator()) def create(self, validated_data): - entities = validated_data.pop('entities') - repository = validated_data.pop('repository') - language = validated_data.pop('language') + entities = validated_data.pop("entities") + repository = validated_data.pop("repository") + language = validated_data.pop("language") repository_update = repository.current_update(language) - validated_data.update({'repository_update': repository_update}) + validated_data.update({"repository_update": repository_update}) evaluate = RepositoryEvaluate.objects.create(**validated_data) for entity in entities: RepositoryEvaluateEntity.objects.create( - repository_evaluate=evaluate, **entity) + repository_evaluate=evaluate, **entity + ) return evaluate def update(self, instance, validated_data): - repository = validated_data.pop('repository') - language = validated_data.get('language', instance.language) + repository = validated_data.pop("repository") + language = validated_data.get("language", instance.language) - instance.text = validated_data.get('text', instance.text) - instance.intent = validated_data.get('intent', instance.intent) + instance.text = validated_data.get("text", instance.text) + instance.intent = validated_data.get("intent", instance.intent) instance.repository_update = repository.current_update(language) instance.save() instance.delete_entities() - for entity in validated_data.pop('entities'): + for entity in validated_data.pop("entities"): RepositoryEvaluateEntity.objects.create( - repository_evaluate=instance, **entity) + repository_evaluate=instance, **entity + ) return instance class RepositoryEvaluateResultVersionsSerializer(serializers.ModelSerializer): - class Meta: model = RepositoryEvaluateResult - fields = [ - 'id', - 'language', - 'created_at', - 'version', - ] + fields = ["id", "language", "created_at", "version"] ref_name = None language = serializers.SerializerMethodField() @@ -124,16 +103,9 @@ def get_language(self, obj): class RepositoryEvaluateResultScore(serializers.ModelSerializer): - class Meta: model = RepositoryEvaluateResultScore - fields = [ - 'precision', - 'f1_score', - 'accuracy', - 'recall', - 'support' - ] + fields = ["precision", "f1_score", "accuracy", "recall", "support"] precision = serializers.SerializerMethodField() f1_score = serializers.SerializerMethodField() @@ -158,26 +130,18 @@ def get_support(self, obj): class RepositoryEvaluateResultIntentSerializer(serializers.ModelSerializer): - class Meta: model = RepositoryEvaluateResultIntent - fields = [ - 'intent', - 'score', - ] + fields = ["intent", "score"] ref_name = None score = RepositoryEvaluateResultScore(read_only=True) class RepositoryEvaluateResultEntitySerializer(serializers.ModelSerializer): - class Meta: model = RepositoryEvaluateResultEntity - fields = [ - 'entity', - 'score', - ] + fields = ["entity", "score"] ref_name = None score = RepositoryEvaluateResultScore(read_only=True) @@ -188,20 +152,19 @@ def get_entity(self, obj): class RepositoryEvaluateResultSerializer(serializers.ModelSerializer): - class Meta: model = RepositoryEvaluateResult fields = [ - 'id', - 'version', - 'created_at', - 'matrix_chart', - 'confidence_chart', - 'log', - 'intents_list', - 'entities_list', - 'intent_results', - 'entity_results', + "id", + "version", + "created_at", + "matrix_chart", + "confidence_chart", + "log", + "intents_list", + "entities_list", + "intent_results", + "entity_results", ] ref_name = None @@ -213,29 +176,27 @@ class Meta: def get_intents_list(self, obj): return RepositoryEvaluateResultIntentSerializer( - obj.evaluate_result_intent.all().exclude(intent__exact=''), - many=True).data + obj.evaluate_result_intent.all().exclude(intent__exact=""), many=True + ).data def get_entities_list(self, obj): return RepositoryEvaluateResultEntitySerializer( - obj.evaluate_result_entity.all(), many=True).data + obj.evaluate_result_entity.all(), many=True + ).data def get_log(self, obj): - intent = self.context.get('request'). \ - query_params.get('intent') - min_confidence = self.context.get('request'). \ - query_params.get('min') - max_confidence = self.context.get('request'). \ - query_params.get('max') + intent = self.context.get("request").query_params.get("intent") + min_confidence = self.context.get("request").query_params.get("min") + max_confidence = self.context.get("request").query_params.get("max") def filter_intent(log, intent, min_confidence, max_confidence): if not intent and not min_confidence and not max_confidence: return log confidence = float( - Decimal( - log.get('intent_prediction').get('confidence') - ).quantize(Decimal('0.00'), rounding=ROUND_DOWN) + Decimal(log.get("intent_prediction").get("confidence")).quantize( + Decimal("0.00"), rounding=ROUND_DOWN + ) ) has_intent = False @@ -244,12 +205,11 @@ def filter_intent(log, intent, min_confidence, max_confidence): min_confidence = float(min_confidence) / 100 max_confidence = float(max_confidence) / 100 - has_intent = True if \ - min_confidence <= \ - confidence <= \ - max_confidence else False + has_intent = ( + True if min_confidence <= confidence <= max_confidence else False + ) - if intent and log.get('intent') != intent: + if intent and log.get("intent") != intent: has_intent = False if has_intent: @@ -259,16 +219,12 @@ def filter_intent(log, intent, min_confidence, max_confidence): None, list( map( - lambda log: - filter_intent( - log, - intent, - min_confidence, - max_confidence + lambda log: filter_intent( + log, intent, min_confidence, max_confidence ), - json.loads(obj.log) + json.loads(obj.log), ) - ) + ), ) return results diff --git a/bothub/api/v2/evaluate/validators.py b/bothub/api/v2/evaluate/validators.py index 371cb1ef..3ac7721e 100644 --- a/bothub/api/v2/evaluate/validators.py +++ b/bothub/api/v2/evaluate/validators.py @@ -3,27 +3,29 @@ class ThereIsIntentValidator(object): - def __call__(self, attrs): - if attrs.get('intent') not in attrs.get('repository').intents: - raise ValidationError(_( - 'Intent MUST match existing intents for training.' - )) + if attrs.get("intent") not in attrs.get("repository").intents: + raise ValidationError(_("Intent MUST match existing intents for training.")) class ThereIsEntityValidator(object): - def __call__(self, attrs): - entities = attrs.get('entities') - repository = attrs.get('repository') + entities = attrs.get("entities") + repository = attrs.get("repository") if entities: - entities_list = list(set( - map(lambda x: x.get('entity'), attrs.get('entities')))) + entities_list = list( + set(map(lambda x: x.get("entity"), attrs.get("entities"))) + ) repository_entities_list = repository.entities.filter( - value__in=entities_list) + value__in=entities_list + ) if len(entities_list) != len(repository_entities_list): - raise ValidationError({'entities': _( - 'Entities MUST match existing entities for training.' - )}) + raise ValidationError( + { + "entities": _( + "Entities MUST match existing entities for training." + ) + } + ) diff --git a/bothub/api/v2/evaluate/views.py b/bothub/api/v2/evaluate/views.py index 6bb6b471..df88d1be 100644 --- a/bothub/api/v2/evaluate/views.py +++ b/bothub/api/v2/evaluate/views.py @@ -27,187 +27,160 @@ @method_decorator( - name='list', + name="list", decorator=swagger_auto_schema( manual_parameters=[ openapi.Parameter( - 'repository_uuid', + "repository_uuid", openapi.IN_QUERY, - description='Repository UUID, calling ' - 'the parameter through url', + description="Repository UUID, calling " "the parameter through url", type=openapi.TYPE_STRING, - required=True - ), + required=True, + ) ] - ) + ), ) @method_decorator( - name='create', + name="create", decorator=swagger_auto_schema( manual_parameters=[ openapi.Parameter( - 'repository_uuid', + "repository_uuid", openapi.IN_QUERY, - description='Repository UUID, calling ' - 'the parameter through url', + description="Repository UUID, calling " "the parameter through url", type=openapi.TYPE_STRING, - required=True - ), + required=True, + ) ] - ) + ), ) @method_decorator( - name='retrieve', + name="retrieve", decorator=swagger_auto_schema( manual_parameters=[ openapi.Parameter( - 'repository_uuid', + "repository_uuid", openapi.IN_QUERY, - description='Repository UUID, calling ' - 'the parameter through url', + description="Repository UUID, calling " "the parameter through url", type=openapi.TYPE_STRING, - required=True - ), + required=True, + ) ] - ) + ), ) @method_decorator( - name='update', + name="update", decorator=swagger_auto_schema( manual_parameters=[ openapi.Parameter( - 'repository_uuid', + "repository_uuid", openapi.IN_QUERY, - description='Repository UUID, calling ' - 'the parameter through url', + description="Repository UUID, calling " "the parameter through url", type=openapi.TYPE_STRING, - required=True - ), + required=True, + ) ] - ) + ), ) @method_decorator( - name='partial_update', + name="partial_update", decorator=swagger_auto_schema( manual_parameters=[ openapi.Parameter( - 'repository_uuid', + "repository_uuid", openapi.IN_QUERY, - description='Repository UUID, calling ' - 'the parameter through url', + description="Repository UUID, calling " "the parameter through url", type=openapi.TYPE_STRING, - required=True - ), + required=True, + ) ] - ) + ), ) @method_decorator( - name='destroy', + name="destroy", decorator=swagger_auto_schema( manual_parameters=[ openapi.Parameter( - 'repository_uuid', + "repository_uuid", openapi.IN_QUERY, - description='Repository UUID, calling ' - 'the parameter through url', + description="Repository UUID, calling " "the parameter through url", type=openapi.TYPE_STRING, - required=True - ), + required=True, + ) ] - ) + ), ) class EvaluateViewSet( - mixins.ListModelMixin, - mixins.CreateModelMixin, - mixins.RetrieveModelMixin, - mixins.UpdateModelMixin, - mixins.DestroyModelMixin, - GenericViewSet): + mixins.ListModelMixin, + mixins.CreateModelMixin, + mixins.RetrieveModelMixin, + mixins.UpdateModelMixin, + mixins.DestroyModelMixin, + GenericViewSet, +): """ Manager evaluate (tests). """ + queryset = RepositoryEvaluate.objects serializer_class = RepositoryEvaluateSerializer - permission_classes = [ - IsAuthenticatedOrReadOnly, - RepositoryEvaluatePermission, - ] + permission_classes = [IsAuthenticatedOrReadOnly, RepositoryEvaluatePermission] metadata_class = Metadata def list(self, request, *args, **kwargs): self.filter_class = EvaluatesFilter - self.filter_backends = [ - OrderingFilter, - SearchFilter, - DjangoFilterBackend, - ] - self.search_fields = [ - '$text', - '^text', - '=text', - ] - self.ordering_fields = [ - 'created_at', - ] + self.filter_backends = [OrderingFilter, SearchFilter, DjangoFilterBackend] + self.search_fields = ["$text", "^text", "=text"] + self.ordering_fields = ["created_at"] return super().list(request, *args, **kwargs) @method_decorator( - name='retrieve', + name="retrieve", decorator=swagger_auto_schema( manual_parameters=[ openapi.Parameter( - 'intent', + "intent", openapi.IN_QUERY, - description='Filter a desired intent', + description="Filter a desired intent", type=openapi.TYPE_STRING, - required=False + required=False, ), openapi.Parameter( - 'min', + "min", openapi.IN_QUERY, - description='Filter Confidence Percentage', + description="Filter Confidence Percentage", type=openapi.TYPE_INTEGER, - required=False + required=False, ), openapi.Parameter( - 'max', + "max", openapi.IN_QUERY, - description='Filter Confidence Percentage', + description="Filter Confidence Percentage", type=openapi.TYPE_INTEGER, - required=False + required=False, ), openapi.Parameter( - 'repository_uuid', + "repository_uuid", openapi.IN_QUERY, - description='Repository UUID, calling ' - 'the parameter through url', + description="Repository UUID, calling " "the parameter through url", type=openapi.TYPE_STRING, - required=True + required=True, ), ] - ) + ), ) class ResultsListViewSet( - mixins.ListModelMixin, - mixins.RetrieveModelMixin, - GenericViewSet): + mixins.ListModelMixin, mixins.RetrieveModelMixin, GenericViewSet +): queryset = RepositoryEvaluateResult.objects serializer_class = RepositoryEvaluateResultVersionsSerializer - permission_classes = [ - IsAuthenticated, - RepositoryEvaluateResultPermission, - ] + permission_classes = [IsAuthenticated, RepositoryEvaluateResultPermission] filter_class = EvaluateResultsFilter - filter_backends = [ - OrderingFilter, - DjangoFilterBackend, - ] - ordering_fields = [ - 'created_at', - ] + filter_backends = [OrderingFilter, DjangoFilterBackend] + ordering_fields = ["created_at"] def retrieve(self, request, *args, **kwargs): self.serializer_class = RepositoryEvaluateResultSerializer diff --git a/bothub/api/v2/example/permissions.py b/bothub/api/v2/example/permissions.py index e8898411..6541b9b3 100644 --- a/bothub/api/v2/example/permissions.py +++ b/bothub/api/v2/example/permissions.py @@ -5,8 +5,9 @@ class RepositoryExamplePermission(permissions.BasePermission): def has_object_permission(self, request, view, obj): - authorization = obj.repository_update.repository \ - .get_user_authorization(request.user) + authorization = obj.repository_update.repository.get_user_authorization( + request.user + ) if request.method in READ_METHODS: return authorization.can_read return authorization.can_contribute diff --git a/bothub/api/v2/example/serializers.py b/bothub/api/v2/example/serializers.py index 84bcab4d..1c51c3c5 100644 --- a/bothub/api/v2/example/serializers.py +++ b/bothub/api/v2/example/serializers.py @@ -13,33 +13,28 @@ class RepositoryExampleEntitySerializer(serializers.ModelSerializer): class Meta: model = RepositoryExampleEntity fields = [ - 'id', - 'repository_example', - 'start', - 'end', - 'entity', - 'label', - 'created_at', - 'value', + "id", + "repository_example", + "start", + "end", + "entity", + "label", + "created_at", + "value", ] ref_name = None repository_example = serializers.PrimaryKeyRelatedField( - queryset=RepositoryExample.objects, - help_text=_('Example\'s ID'), - required=False) + queryset=RepositoryExample.objects, help_text=_("Example's ID"), required=False + ) entity = EntityValueField() - label = LabelValueField( - allow_blank=True, - required=False) + label = LabelValueField(allow_blank=True, required=False) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - if kwargs.get('data') == 'GET': - self.fields['label'] = serializers.SerializerMethodField( - required=False - ) + if kwargs.get("data") == "GET": + self.fields["label"] = serializers.SerializerMethodField(required=False) self.validators.append(EntityNotEqualLabelValidator()) def get_label(self, obj): @@ -48,15 +43,15 @@ def get_label(self, obj): return obj.entity.label.value def create(self, validated_data): - repository_example = validated_data.pop('repository_example', None) + repository_example = validated_data.pop("repository_example", None) assert repository_example - label = validated_data.pop('label', empty) + label = validated_data.pop("label", empty) example_entity = self.Meta.model.objects.create( - repository_example=repository_example, - **validated_data) + repository_example=repository_example, **validated_data + ) if label is not empty: example_entity.entity.set_label(label) - example_entity.entity.save(update_fields=['label']) + example_entity.entity.save(update_fields=["label"]) return example_entity @@ -64,23 +59,17 @@ class RepositoryExampleSerializer(serializers.ModelSerializer): class Meta: model = RepositoryExample fields = [ - 'id', - 'repository_update', - 'deleted_in', - 'text', - 'intent', - 'language', - 'created_at', - 'entities', - 'translations', - ] - read_only_fields = [ - 'repository_update', - 'deleted_in', - 'translations', + "id", + "repository_update", + "deleted_in", + "text", + "intent", + "language", + "created_at", + "entities", + "translations", ] + read_only_fields = ["repository_update", "deleted_in", "translations"] ref_name = None - entities = RepositoryExampleEntitySerializer( - many=True, - read_only=True) + entities = RepositoryExampleEntitySerializer(many=True, read_only=True) diff --git a/bothub/api/v2/examples/filters.py b/bothub/api/v2/examples/filters.py index 7ef32498..e6db69bb 100644 --- a/bothub/api/v2/examples/filters.py +++ b/bothub/api/v2/examples/filters.py @@ -13,40 +13,42 @@ class ExamplesFilter(filters.FilterSet): class Meta: model = RepositoryExample - fields = [ - 'text', - 'language', - 'intent', - ] + fields = ["text", "language", "intent"] repository_uuid = filters.CharFilter( - field_name='repository_uuid', - method='filter_repository_uuid', + field_name="repository_uuid", + method="filter_repository_uuid", required=True, - help_text=_('Repository\'s UUID')) + help_text=_("Repository's UUID"), + ) language = filters.CharFilter( - field_name='language', - method='filter_language', - help_text='Filter by language, default is repository base language') + field_name="language", + method="filter_language", + help_text="Filter by language, default is repository base language", + ) has_translation = filters.BooleanFilter( - field_name='has_translation', - method='filter_has_translation', - help_text=_('Filter for examples with or without translation')) + field_name="has_translation", + method="filter_has_translation", + help_text=_("Filter for examples with or without translation"), + ) has_not_translation_to = filters.CharFilter( - field_name='has_not_translation_to', - method='filter_has_not_translation_to') + field_name="has_not_translation_to", method="filter_has_not_translation_to" + ) order_by_translation = filters.CharFilter( - field_name='order_by_translation', - method='filter_order_by_translation', - help_text=_('Order examples with translation by language')) + field_name="order_by_translation", + method="filter_order_by_translation", + help_text=_("Order examples with translation by language"), + ) label = filters.CharFilter( - field_name='label', - method='filter_label', - help_text=_('Filter for examples with entities with specific label.')) + field_name="label", + method="filter_label", + help_text=_("Filter for examples with entities with specific label."), + ) entity = filters.CharFilter( - field_name='entity', - method='filter_entity', - help_text=_('Filter for examples with entity.')) + field_name="entity", + method="filter_entity", + help_text=_("Filter for examples with entity."), + ) def filter_repository_uuid(self, queryset, name, value): request = self.request @@ -57,44 +59,43 @@ def filter_repository_uuid(self, queryset, name, value): raise PermissionDenied() return repository.examples(queryset=queryset) except Repository.DoesNotExist: - raise NotFound( - _('Repository {} does not exist').format(value)) + raise NotFound(_("Repository {} does not exist").format(value)) except DjangoValidationError: - raise NotFound(_('Invalid repository_uuid')) + raise NotFound(_("Invalid repository_uuid")) def filter_language(self, queryset, name, value): return queryset.filter(repository_update__language=value) def filter_has_translation(self, queryset, name, value): - annotated_queryset = queryset.annotate( - translation_count=Count('translations')) + annotated_queryset = queryset.annotate(translation_count=Count("translations")) if value: - return annotated_queryset.filter( - translation_count__gt=0) + return annotated_queryset.filter(translation_count__gt=0) else: - return annotated_queryset.filter( - translation_count=0) + return annotated_queryset.filter(translation_count=0) def filter_has_not_translation_to(self, queryset, name, value): annotated_queryset = queryset.annotate( translation_count=Count( - 'translations', - filter=Q(translations__language=value))) + "translations", filter=Q(translations__language=value) + ) + ) return annotated_queryset.filter(translation_count=0) def filter_order_by_translation(self, queryset, name, value): - inverted = value[0] == '-' + inverted = value[0] == "-" language = value[1:] if inverted else value result_queryset = queryset.annotate( translation_count=Count( - 'translations', - filter=Q(translations__language=language))) + "translations", filter=Q(translations__language=language) + ) + ) result_queryset = result_queryset.order_by( - '-translation_count' if inverted else 'translation_count') + "-translation_count" if inverted else "translation_count" + ) return result_queryset def filter_label(self, queryset, name, value): - if value == 'other': + if value == "other": return queryset.filter(entities__entity__label__isnull=True) return queryset.filter(entities__entity__label__value=value) diff --git a/bothub/api/v2/examples/views.py b/bothub/api/v2/examples/views.py index 46a0360b..f5fbc6b5 100644 --- a/bothub/api/v2/examples/views.py +++ b/bothub/api/v2/examples/views.py @@ -11,25 +11,11 @@ from .filters import ExamplesFilter -class ExamplesViewSet( - mixins.ListModelMixin, - GenericViewSet): +class ExamplesViewSet(mixins.ListModelMixin, GenericViewSet): queryset = RepositoryExample.objects serializer_class = RepositoryExampleSerializer filter_class = ExamplesFilter - filter_backends = [ - OrderingFilter, - SearchFilter, - DjangoFilterBackend, - ] - search_fields = [ - '$text', - '^text', - '=text', - ] - ordering_fields = [ - 'created_at', - ] - permission_classes = [ - RepositoryExamplePermission, - ] + filter_backends = [OrderingFilter, SearchFilter, DjangoFilterBackend] + search_fields = ["$text", "^text", "=text"] + ordering_fields = ["created_at"] + permission_classes = [RepositoryExamplePermission] diff --git a/bothub/api/v2/fields.py b/bothub/api/v2/fields.py index 29895512..63f86cf4 100644 --- a/bothub/api/v2/fields.py +++ b/bothub/api/v2/fields.py @@ -14,7 +14,7 @@ class TextField(serializers.CharField): class PasswordField(serializers.CharField): def __init__(self, *args, **kwargs): - kwargs.pop('trim_whitespace', None) + kwargs.pop("trim_whitespace", None) super().__init__(trim_whitespace=False, **kwargs) @@ -24,16 +24,17 @@ class EntityText(serializers.CharField): class EntityValueField(serializers.CharField): def __init__(self, *args, validators=[], **kwargs): - kwargs.pop('max_length', 0) - kwargs.pop('help_text', '') + kwargs.pop("max_length", 0) + kwargs.pop("help_text", "") - value_field = RepositoryEntity._meta.get_field('value') + value_field = RepositoryEntity._meta.get_field("value") super().__init__( *args, max_length=value_field.max_length, validators=(validators + value_field.validators), - **kwargs) + **kwargs + ) def to_representation(self, obj): return obj.value # pragma: no cover @@ -41,16 +42,17 @@ def to_representation(self, obj): class LabelValueField(serializers.CharField): # pragma: no cover def __init__(self, *args, validators=[], **kwargs): - kwargs.pop('max_length', 0) - kwargs.pop('help_text', '') + kwargs.pop("max_length", 0) + kwargs.pop("help_text", "") - value_field = RepositoryEntityLabel._meta.get_field('value') + value_field = RepositoryEntityLabel._meta.get_field("value") super().__init__( *args, max_length=value_field.max_length, validators=(validators + value_field.validators), - **kwargs) + **kwargs + ) def to_representation(self, obj): return obj.value # pragma: no cover diff --git a/bothub/api/v2/metadata.py b/bothub/api/v2/metadata.py index 24ffd14d..e436cd99 100644 --- a/bothub/api/v2/metadata.py +++ b/bothub/api/v2/metadata.py @@ -12,107 +12,105 @@ class Metadata(BaseMetadata): - label_lookup = ClassLookupDict({ - serializers.Field: 'field', - serializers.BooleanField: 'boolean', - serializers.NullBooleanField: 'boolean', - serializers.CharField: 'string', - serializers.URLField: 'url', - serializers.EmailField: 'email', - serializers.RegexField: 'regex', - serializers.SlugField: 'slug', - serializers.IntegerField: 'integer', - serializers.FloatField: 'float', - serializers.DecimalField: 'decimal', - serializers.DateField: 'date', - serializers.DateTimeField: 'date', - serializers.TimeField: 'time', - serializers.ChoiceField: 'choice', - serializers.MultipleChoiceField: 'multiple choice', - serializers.FileField: 'file upload', - serializers.ImageField: 'image upload', - serializers.ListField: 'list', - serializers.DictField: 'nested object', - serializers.Serializer: 'nested object', - serializers.ManyRelatedField: 'multiple choice', - serializers.HiddenField: 'hidden', - PasswordField: 'password', - ModelMultipleChoiceField: 'multiple choice', - TextField: 'text', - EntityText: 'entity text', - }) + label_lookup = ClassLookupDict( + { + serializers.Field: "field", + serializers.BooleanField: "boolean", + serializers.NullBooleanField: "boolean", + serializers.CharField: "string", + serializers.URLField: "url", + serializers.EmailField: "email", + serializers.RegexField: "regex", + serializers.SlugField: "slug", + serializers.IntegerField: "integer", + serializers.FloatField: "float", + serializers.DecimalField: "decimal", + serializers.DateField: "date", + serializers.DateTimeField: "date", + serializers.TimeField: "time", + serializers.ChoiceField: "choice", + serializers.MultipleChoiceField: "multiple choice", + serializers.FileField: "file upload", + serializers.ImageField: "image upload", + serializers.ListField: "list", + serializers.DictField: "nested object", + serializers.Serializer: "nested object", + serializers.ManyRelatedField: "multiple choice", + serializers.HiddenField: "hidden", + PasswordField: "password", + ModelMultipleChoiceField: "multiple choice", + TextField: "text", + EntityText: "entity text", + } + ) def determine_metadata(self, request, view): # pragma: no cover metadata = OrderedDict() - metadata['name'] = view.get_view_name() - metadata['description'] = view.get_view_description() - metadata['renders'] = [ - renderer.media_type - for renderer in view.renderer_classes + metadata["name"] = view.get_view_name() + metadata["description"] = view.get_view_description() + metadata["renders"] = [ + renderer.media_type for renderer in view.renderer_classes ] - metadata['parses'] = [ - parser.media_type - for parser in view.parser_classes - ] - if hasattr(view, 'get_serializer'): + metadata["parses"] = [parser.media_type for parser in view.parser_classes] + if hasattr(view, "get_serializer"): actions = self.determine_actions(request, view) if actions: - metadata['actions'] = actions + metadata["actions"] = actions return metadata def determine_actions(self, request, view): # pragma: no cover actions = {} - for method in {'PUT', 'POST'} & set(view.allowed_methods): + for method in {"PUT", "POST"} & set(view.allowed_methods): serializer = view.get_serializer() actions[method] = self.get_serializer_info(serializer) view.request = request return actions def get_serializer_info(self, serializer): # pragma: no cover - if hasattr(serializer, 'child'): + if hasattr(serializer, "child"): serializer = serializer.child - return OrderedDict([ - (field_name, self.get_field_info(field)) - for field_name, field in serializer.fields.items() - ]) + return OrderedDict( + [ + (field_name, self.get_field_info(field)) + for field_name, field in serializer.fields.items() + ] + ) def get_field_info(self, field): # pragma: no cover field_info = OrderedDict() - field_info['type'] = self.label_lookup[field] or 'field' - field_info['required'] = getattr(field, 'required', False) + field_info["type"] = self.label_lookup[field] or "field" + field_info["required"] = getattr(field, "required", False) attrs = [ - 'read_only', - 'label', - 'help_text', - 'min_length', - 'max_length', - 'min_value', - 'max_value', - 'style', + "read_only", + "label", + "help_text", + "min_length", + "max_length", + "min_value", + "max_value", + "style", ] for attr in attrs: value = getattr(field, attr, None) - if value is not None and value != '': - field_info[attr] = value if isinstance( - value, - dict, - ) else force_text( - value, - strings_only=True, + if value is not None and value != "": + field_info[attr] = ( + value + if isinstance(value, dict) + else force_text(value, strings_only=True) ) - if getattr(field, 'child', None): - field_info['child'] = self.get_field_info(field.child) - elif getattr(field, 'fields', None): - field_info['children'] = self.get_serializer_info(field) + if getattr(field, "child", None): + field_info["child"] = self.get_field_info(field.child) + elif getattr(field, "fields", None): + field_info["children"] = self.get_serializer_info(field) - if (not field_info.get('read_only') and hasattr(field, 'choices')): - field_info['choices'] = [ + if not field_info.get("read_only") and hasattr(field, "choices"): + field_info["choices"] = [ { - 'value': choice_value, - 'display_name': force_text(choice_name, strings_only=True) + "value": choice_value, + "display_name": force_text(choice_name, strings_only=True), } for choice_value, choice_name in field.choices.items() ] diff --git a/bothub/api/v2/nlp/views.py b/bothub/api/v2/nlp/views.py index b72a7344..4ce34296 100644 --- a/bothub/api/v2/nlp/views.py +++ b/bothub/api/v2/nlp/views.py @@ -30,18 +30,17 @@ def check_auth(request): try: - auth = request.META.get('HTTP_AUTHORIZATION').split() + auth = request.META.get("HTTP_AUTHORIZATION").split() auth = auth[1] RepositoryAuthorization.objects.get(uuid=auth) except Exception: - msg = _('Invalid token header.') + msg = _("Invalid token header.") raise exceptions.AuthenticationFailed(msg) class RepositoryAuthorizationTrainViewSet( - mixins.RetrieveModelMixin, - mixins.CreateModelMixin, - GenericViewSet): + mixins.RetrieveModelMixin, mixins.CreateModelMixin, GenericViewSet +): queryset = RepositoryAuthorization.objects serializer_class = NLPSerializer permission_classes = [AllowAny] @@ -50,192 +49,138 @@ def retrieve(self, request, *args, **kwargs): check_auth(request) repository_authorization = self.get_object() current_update = repository_authorization.repository.current_update( - str(request.query_params.get('language')) + str(request.query_params.get("language")) ) - return Response({ - 'ready_for_train': - current_update.ready_for_train, - 'current_update_id': - current_update.id, - 'repository_authorization_user_id': - repository_authorization.user.id, - 'language': - current_update.language - }) + return Response( + { + "ready_for_train": current_update.ready_for_train, + "current_update_id": current_update.id, + "repository_authorization_user_id": repository_authorization.user.id, + "language": current_update.language, + } + ) - @action( - detail=True, - methods=['POST'], - url_name='start_training', - lookup_field=[]) + @action(detail=True, methods=["POST"], url_name="start_training", lookup_field=[]) def start_training(self, request, **kwargs): check_auth(request) repository = get_object_or_404( - RepositoryUpdate, - pk=request.data.get('update_id') + RepositoryUpdate, pk=request.data.get("update_id") ) examples = [ - { - 'example_id': example.id, - 'example_intent': example.intent - } for example in repository.examples + {"example_id": example.id, "example_intent": example.intent} + for example in repository.examples ] repository.start_training( - get_object_or_404(User, pk=request.data.get('by_user')) + get_object_or_404(User, pk=request.data.get("by_user")) ) label_examples_query = [] - for label_examples in repository.examples.filter( - entities__entity__label__isnull=False - ).annotate( - entities_count=models.Count('entities') - ).filter( - entities_count__gt=0): - label_examples_query.append( - { - 'example_id': label_examples.id - } - ) + for label_examples in ( + repository.examples.filter(entities__entity__label__isnull=False) + .annotate(entities_count=models.Count("entities")) + .filter(entities_count__gt=0) + ): + label_examples_query.append({"example_id": label_examples.id}) - return Response({ - 'language': repository.language, - 'update_id': repository.id, - 'repository_uuid': str(repository.repository.uuid), - 'examples': examples, - 'label_examples_query': label_examples_query, - 'intent': repository.intents, - 'algorithm': repository.algorithm, - 'use_name_entities': repository.use_name_entities, - 'use_competing_intents': repository.use_competing_intents, - 'ALGORITHM_STATISTICAL_MODEL': - Repository.ALGORITHM_STATISTICAL_MODEL, - 'ALGORITHM_NEURAL_NETWORK_EXTERNAL': - Repository.ALGORITHM_NEURAL_NETWORK_EXTERNAL - }) + return Response( + { + "language": repository.language, + "update_id": repository.id, + "repository_uuid": str(repository.repository.uuid), + "examples": examples, + "label_examples_query": label_examples_query, + "intent": repository.intents, + "algorithm": repository.algorithm, + "use_name_entities": repository.use_name_entities, + "use_competing_intents": repository.use_competing_intents, + "ALGORITHM_STATISTICAL_MODEL": Repository.ALGORITHM_STATISTICAL_MODEL, + "ALGORITHM_NEURAL_NETWORK_EXTERNAL": Repository.ALGORITHM_NEURAL_NETWORK_EXTERNAL, + } + ) - @action( - detail=True, - methods=['GET'], - url_name='gettext', - lookup_field=[]) + @action(detail=True, methods=["GET"], url_name="gettext", lookup_field=[]) def get_text(self, request, **kwargs): check_auth(request) try: - update_id = int(request.query_params.get('update_id')) - example_id = int(request.query_params.get('example_id')) + update_id = int(request.query_params.get("update_id")) + example_id = int(request.query_params.get("example_id")) except ValueError: raise exceptions.NotFound() repository = get_object_or_404( - get_object_or_404( - RepositoryUpdate, - pk=update_id - ).examples, pk=example_id - ).get_text(request.query_params.get('language')) + get_object_or_404(RepositoryUpdate, pk=update_id).examples, pk=example_id + ).get_text(request.query_params.get("language")) - return Response({ - 'get_text': repository - }) + return Response({"get_text": repository}) - @action( - detail=True, - methods=['GET'], - url_name='get_entities', - lookup_field=[]) + @action(detail=True, methods=["GET"], url_name="get_entities", lookup_field=[]) def get_entities(self, request, **kwargs): check_auth(request) try: - update_id = int(request.query_params.get('update_id')) - example_id = int(request.query_params.get('example_id')) + update_id = int(request.query_params.get("update_id")) + example_id = int(request.query_params.get("example_id")) except ValueError: raise exceptions.NotFound() repository = get_object_or_404( - get_object_or_404( - RepositoryUpdate, - pk=update_id - ).examples, pk=example_id - ).get_entities(request.query_params.get('language')) + get_object_or_404(RepositoryUpdate, pk=update_id).examples, pk=example_id + ).get_entities(request.query_params.get("language")) entities = [entit.rasa_nlu_data for entit in repository] - return Response({ - 'entities': entities, - }) + return Response({"entities": entities}) @action( - detail=True, - methods=['GET'], - url_name='get_entities_label', - lookup_field=[]) + detail=True, methods=["GET"], url_name="get_entities_label", lookup_field=[] + ) def get_entities_label(self, request, **kwargs): check_auth(request) try: - update_id = int(request.query_params.get('update_id')) - example_id = int(request.query_params.get('example_id')) + update_id = int(request.query_params.get("update_id")) + example_id = int(request.query_params.get("example_id")) except ValueError: raise exceptions.NotFound() repository = get_object_or_404( - get_object_or_404( - RepositoryUpdate, - pk=update_id - ).examples, pk=example_id - ).get_entities(request.query_params.get('language')) + get_object_or_404(RepositoryUpdate, pk=update_id).examples, pk=example_id + ).get_entities(request.query_params.get("language")) entities = [ - example_entity.get_rasa_nlu_data( - label_as_entity=True - ) for example_entity in filter( - lambda ee: ee.entity.label, repository - ) + example_entity.get_rasa_nlu_data(label_as_entity=True) + for example_entity in filter(lambda ee: ee.entity.label, repository) ] - return Response({ - 'entities': entities, - }) + return Response({"entities": entities}) - @action( - detail=True, - methods=['POST'], - url_name='train_fail', - lookup_field=[]) + @action(detail=True, methods=["POST"], url_name="train_fail", lookup_field=[]) def train_fail(self, request, **kwargs): check_auth(request) repository = get_object_or_404( - RepositoryUpdate, - pk=request.data.get('update_id') + RepositoryUpdate, pk=request.data.get("update_id") ) repository.train_fail() return Response({}) - @action( - detail=True, - methods=['POST'], - url_name='training_log', - lookup_field=[]) + @action(detail=True, methods=["POST"], url_name="training_log", lookup_field=[]) def training_log(self, request, **kwargs): check_auth(request) repository = get_object_or_404( - RepositoryUpdate, - pk=request.data.get('update_id') + RepositoryUpdate, pk=request.data.get("update_id") ) - repository.training_log = request.data.get('training_log') - repository.save(update_fields=['training_log']) + repository.training_log = request.data.get("training_log") + repository.save(update_fields=["training_log"]) return Response({}) -class RepositoryAuthorizationParseViewSet( - mixins.RetrieveModelMixin, - GenericViewSet): +class RepositoryAuthorizationParseViewSet(mixins.RetrieveModelMixin, GenericViewSet): queryset = RepositoryAuthorization.objects serializer_class = NLPSerializer permission_classes = [AllowAny] @@ -245,40 +190,37 @@ def retrieve(self, request, *args, **kwargs): repository_authorization = self.get_object() repository = repository_authorization.repository update = repository.last_trained_update( - str(request.query_params.get('language')) + str(request.query_params.get("language")) + ) + return Response( + { + "update": False if update is None else True, + "update_id": update.id, + "language": update.language, + } ) - return Response({ - 'update': False if update is None else True, - 'update_id': update.id, - 'language': update.language - }) - @action( - detail=True, - methods=['GET'], - url_name='repository_entity', - lookup_field=[]) + @action(detail=True, methods=["GET"], url_name="repository_entity", lookup_field=[]) def repository_entity(self, request, **kwargs): check_auth(request) repository_update = get_object_or_404( - RepositoryUpdate, - pk=request.query_params.get('update_id') + RepositoryUpdate, pk=request.query_params.get("update_id") ) repository_entity = get_object_or_404( RepositoryEntity, repository=repository_update.repository, - value=request.query_params.get('entity') + value=request.query_params.get("entity"), ) - return Response({ - 'label': repository_entity.label, - 'label_value': repository_entity.label.value - }) + return Response( + { + "label": repository_entity.label, + "label_value": repository_entity.label.value, + } + ) -class RepositoryAuthorizationInfoViewSet( - mixins.RetrieveModelMixin, - GenericViewSet): +class RepositoryAuthorizationInfoViewSet(mixins.RetrieveModelMixin, GenericViewSet): queryset = RepositoryAuthorization.objects serializer_class = NLPSerializer permission_classes = [AllowAny] @@ -291,9 +233,7 @@ def retrieve(self, request, *args, **kwargs): return Response(serializer.data) -class RepositoryAuthorizationEvaluateViewSet( - mixins.RetrieveModelMixin, - GenericViewSet): +class RepositoryAuthorizationEvaluateViewSet(mixins.RetrieveModelMixin, GenericViewSet): queryset = RepositoryAuthorization.objects serializer_class = NLPSerializer permission_classes = [AllowAny] @@ -303,25 +243,22 @@ def retrieve(self, request, *args, **kwargs): repository_authorization = self.get_object() repository = repository_authorization.repository update = repository.last_trained_update( - str(request.query_params.get('language')) + str(request.query_params.get("language")) + ) + return Response( + { + "update": False if update is None else True, + "update_id": update.id, + "language": update.language, + "user_id": repository_authorization.user.id, + } ) - return Response({ - 'update': False if update is None else True, - 'update_id': update.id, - 'language': update.language, - 'user_id': repository_authorization.user.id - }) - @action( - detail=True, - methods=['GET'], - url_name='evaluations', - lookup_field=[]) + @action(detail=True, methods=["GET"], url_name="evaluations", lookup_field=[]) def evaluations(self, request, **kwargs): check_auth(request) repository_update = get_object_or_404( - RepositoryUpdate, - pk=request.query_params.get('update_id') + RepositoryUpdate, pk=request.query_params.get("update_id") ) evaluations = repository_update.repository.evaluations( language=repository_update.language @@ -332,93 +269,84 @@ def evaluations(self, request, **kwargs): for evaluate in evaluations: entities = [] - for evaluate_entity in evaluate.get_entities( - repository_update.language - ): + for evaluate_entity in evaluate.get_entities(repository_update.language): entities.append( { - 'start': evaluate_entity.start, - 'end': evaluate_entity.end, - 'value': - evaluate.text[ - evaluate_entity.start:evaluate_entity.end - ], - 'entity': evaluate_entity.entity.value, + "start": evaluate_entity.start, + "end": evaluate_entity.end, + "value": evaluate.text[ + evaluate_entity.start : evaluate_entity.end + ], + "entity": evaluate_entity.entity.value, } ) data.append( { - 'text': evaluate.get_text(repository_update.language), - 'intent': evaluate.intent, - 'entities': entities - + "text": evaluate.get_text(repository_update.language), + "intent": evaluate.intent, + "entities": entities, } ) return Response(data) - @action( - detail=True, - methods=['POST'], - url_name='evaluate_results', - lookup_field=[]) + @action(detail=True, methods=["POST"], url_name="evaluate_results", lookup_field=[]) def evaluate_results(self, request, **kwargs): check_auth(request) repository_update = get_object_or_404( - RepositoryUpdate, - pk=request.data.get('update_id') + RepositoryUpdate, pk=request.data.get("update_id") ) intents_score = RepositoryEvaluateResultScore.objects.create( - precision=request.data.get('intentprecision'), - f1_score=request.data.get('intentf1_score'), - accuracy=request.data.get('intentaccuracy'), + precision=request.data.get("intentprecision"), + f1_score=request.data.get("intentf1_score"), + accuracy=request.data.get("intentaccuracy"), ) entities_score = RepositoryEvaluateResultScore.objects.create( - precision=request.data.get('entityprecision'), - f1_score=request.data.get('entityf1_score'), - accuracy=request.data.get('entityaccuracy'), + precision=request.data.get("entityprecision"), + f1_score=request.data.get("entityf1_score"), + accuracy=request.data.get("entityaccuracy"), ) evaluate_result = RepositoryEvaluateResult.objects.create( repository_update=repository_update, entity_results=entities_score, intent_results=intents_score, - matrix_chart=request.data.get('matrix_chart'), - confidence_chart=request.data.get('confidence_chart'), - log=json.dumps(request.data.get('log')), + matrix_chart=request.data.get("matrix_chart"), + confidence_chart=request.data.get("confidence_chart"), + log=json.dumps(request.data.get("log")), ) return Response( { - 'evaluate_id': evaluate_result.id, - 'evaluate_version': evaluate_result.version + "evaluate_id": evaluate_result.id, + "evaluate_version": evaluate_result.version, } ) @action( detail=True, - methods=['POST'], - url_name='evaluate_results_intent', - lookup_field=[]) + methods=["POST"], + url_name="evaluate_results_intent", + lookup_field=[], + ) def evaluate_results_intent(self, request, **kwargs): check_auth(request) evaluate_result = get_object_or_404( - RepositoryEvaluateResult, - pk=request.data.get('evaluate_id') + RepositoryEvaluateResult, pk=request.data.get("evaluate_id") ) intent_score = RepositoryEvaluateResultScore.objects.create( - precision=request.data.get('precision'), - recall=request.data.get('recall'), - f1_score=request.data.get('f1_score'), - support=request.data.get('support'), + precision=request.data.get("precision"), + recall=request.data.get("recall"), + f1_score=request.data.get("f1_score"), + support=request.data.get("support"), ) RepositoryEvaluateResultIntent.objects.create( - intent=request.data.get('intent_key'), + intent=request.data.get("intent_key"), evaluate_result=evaluate_result, score=intent_score, ) @@ -427,34 +355,34 @@ def evaluate_results_intent(self, request, **kwargs): @action( detail=True, - methods=['POST'], - url_name='evaluate_results_score', - lookup_field=[]) + methods=["POST"], + url_name="evaluate_results_score", + lookup_field=[], + ) def evaluate_results_score(self, request, **kwargs): check_auth(request) evaluate_result = get_object_or_404( - RepositoryEvaluateResult, - pk=request.data.get('evaluate_id') + RepositoryEvaluateResult, pk=request.data.get("evaluate_id") ) repository_update = get_object_or_404( - RepositoryUpdate, - pk=request.data.get('update_id') + RepositoryUpdate, pk=request.data.get("update_id") ) entity_score = RepositoryEvaluateResultScore.objects.create( - precision=request.data.get('precision'), - recall=request.data.get('recall'), - f1_score=request.data.get('f1_score'), - support=request.data.get('support'), + precision=request.data.get("precision"), + recall=request.data.get("recall"), + f1_score=request.data.get("f1_score"), + support=request.data.get("support"), ) RepositoryEvaluateResultEntity.objects.create( entity=RepositoryEntity.objects.get( repository=repository_update.repository, - value=request.data.get('entity_key'), - create_entity=False), + value=request.data.get("entity_key"), + create_entity=False, + ), evaluate_result=evaluate_result, score=entity_score, ) @@ -462,38 +390,26 @@ def evaluate_results_score(self, request, **kwargs): return Response({}) -class NLPLangsViewSet( - mixins.ListModelMixin, - GenericViewSet): +class NLPLangsViewSet(mixins.ListModelMixin, GenericViewSet): queryset = RepositoryAuthorization.objects serializer_class = NLPSerializer permission_classes = [AllowAny] def list(self, request, *args, **kwargs): - return Response({ - 'english': [ - languages.LANGUAGE_EN, - ], - 'portuguese': [ - languages.LANGUAGE_PT, - languages.LANGUAGE_PT_BR, - ], - languages.LANGUAGE_PT: [ - languages.LANGUAGE_PT_BR, - ], - 'pt-br': [ - languages.LANGUAGE_PT_BR, - ], - 'br': [ - languages.LANGUAGE_PT_BR, - ], - }) + return Response( + { + "english": [languages.LANGUAGE_EN], + "portuguese": [languages.LANGUAGE_PT, languages.LANGUAGE_PT_BR], + languages.LANGUAGE_PT: [languages.LANGUAGE_PT_BR], + "pt-br": [languages.LANGUAGE_PT_BR], + "br": [languages.LANGUAGE_PT_BR], + } + ) class RepositoryUpdateInterpretersViewSet( - mixins.RetrieveModelMixin, - mixins.CreateModelMixin, - GenericViewSet): + mixins.RetrieveModelMixin, mixins.CreateModelMixin, GenericViewSet +): queryset = RepositoryUpdate.objects serializer_class = NLPSerializer permission_classes = [AllowAny] @@ -505,20 +421,19 @@ def retrieve(self, request, *args, **kwargs): download = requests.get(update.bot_data) bot_data = base64.b64encode(download.content) except Exception: - bot_data = b'' - return Response({ - 'update_id': update.id, - 'repository_uuid': update.repository.uuid, - 'bot_data': str(bot_data) - }) + bot_data = b"" + return Response( + { + "update_id": update.id, + "repository_uuid": update.repository.uuid, + "bot_data": str(bot_data), + } + ) def create(self, request, *args, **kwargs): check_auth(request) - id = request.data.get('id') - repository = get_object_or_404( - RepositoryUpdate, - pk=id - ) - bot_data = base64.b64decode(request.data.get('bot_data')) + id = request.data.get("id") + repository = get_object_or_404(RepositoryUpdate, pk=id) + bot_data = base64.b64decode(request.data.get("bot_data")) repository.save_training(send_bot_data_file_aws(id, bot_data)) return Response({}) diff --git a/bothub/api/v2/repository/filters.py b/bothub/api/v2/repository/filters.py index 9445f7e4..5a3e692a 100644 --- a/bothub/api/v2/repository/filters.py +++ b/bothub/api/v2/repository/filters.py @@ -13,15 +13,11 @@ class RepositoriesFilter(filters.FilterSet): class Meta: model = Repository - fields = [ - 'name', - 'categories', - ] + fields = ["name", "categories"] language = filters.CharFilter( - field_name='language', - method='filter_language', - help_text=_('Language')) + field_name="language", method="filter_language", help_text=_("Language") + ) def filter_language(self, queryset, name, value): return queryset.supported_language(value) @@ -30,12 +26,13 @@ def filter_language(self, queryset, name, value): class RepositoryAuthorizationFilter(filters.FilterSet): class Meta: model = RepositoryAuthorization - fields = ['repository'] + fields = ["repository"] repository = filters.CharFilter( - field_name='repository', - method='filter_repository_uuid', - help_text=_('Repository\'s UUID')) + field_name="repository", + method="filter_repository_uuid", + help_text=_("Repository's UUID"), + ) def filter_repository_uuid(self, queryset, name, value): request = self.request @@ -46,22 +43,22 @@ def filter_repository_uuid(self, queryset, name, value): raise PermissionDenied() return queryset.filter(repository=repository) except Repository.DoesNotExist: - raise NotFound( - _('Repository {} does not exist').format(value)) + raise NotFound(_("Repository {} does not exist").format(value)) except DjangoValidationError: - raise NotFound(_('Invalid repository UUID')) + raise NotFound(_("Invalid repository UUID")) class RepositoryAuthorizationRequestsFilter(filters.FilterSet): class Meta: model = RequestRepositoryAuthorization - fields = ['repository_uuid'] + fields = ["repository_uuid"] repository_uuid = filters.CharFilter( - field_name='repository_uuid', + field_name="repository_uuid", required=True, - method='filter_repository_uuid', - help_text=_('Repository\'s UUID')) + method="filter_repository_uuid", + help_text=_("Repository's UUID"), + ) def filter_repository_uuid(self, queryset, name, value): request = self.request @@ -72,24 +69,22 @@ def filter_repository_uuid(self, queryset, name, value): raise PermissionDenied() return queryset.filter(repository=repository) except Repository.DoesNotExist: - raise NotFound( - _('Repository {} does not exist').format(value)) + raise NotFound(_("Repository {} does not exist").format(value)) except DjangoValidationError: - raise NotFound(_('Invalid repository UUID')) + raise NotFound(_("Invalid repository UUID")) class RepositoryUpdatesFilter(filters.FilterSet): class Meta: model = RepositoryUpdate - fields = [ - 'repository_uuid', - ] + fields = ["repository_uuid"] repository_uuid = filters.CharFilter( - field_name='repository_uuid', + field_name="repository_uuid", required=True, - method='filter_repository_uuid', - help_text=_('Repository\'s UUID')) + method="filter_repository_uuid", + help_text=_("Repository's UUID"), + ) def filter_repository_uuid(self, queryset, name, value): request = self.request @@ -100,7 +95,6 @@ def filter_repository_uuid(self, queryset, name, value): raise PermissionDenied() return queryset.filter(repository=repository) except Repository.DoesNotExist: - raise NotFound( - _('Repository {} does not exist').format(value)) + raise NotFound(_("Repository {} does not exist").format(value)) except DjangoValidationError: - raise NotFound(_('Invalid repository UUID')) + raise NotFound(_("Invalid repository UUID")) diff --git a/bothub/api/v2/repository/permissions.py b/bothub/api/v2/repository/permissions.py index 61631893..f96473e7 100644 --- a/bothub/api/v2/repository/permissions.py +++ b/bothub/api/v2/repository/permissions.py @@ -7,8 +7,7 @@ class RepositoryPermission(permissions.BasePermission): def has_object_permission(self, request, view, obj): authorization = obj.get_user_authorization(request.user) - if request.method in READ_METHODS and \ - not request.user.is_authenticated: + if request.method in READ_METHODS and not request.user.is_authenticated: return authorization.can_read if request.user.is_authenticated: @@ -28,8 +27,9 @@ def has_object_permission(self, request, view, obj): class RepositoryExamplePermission(permissions.BasePermission): def has_object_permission(self, request, view, obj): - authorization = obj.repository_update.repository \ - .get_user_authorization(request.user) + authorization = obj.repository_update.repository.get_user_authorization( + request.user + ) if request.method in READ_METHODS: return authorization.can_read return authorization.can_contribute diff --git a/bothub/api/v2/repository/serializers.py b/bothub/api/v2/repository/serializers.py index c3f39f30..a7cdfd97 100644 --- a/bothub/api/v2/repository/serializers.py +++ b/bothub/api/v2/repository/serializers.py @@ -3,18 +3,15 @@ from rest_framework import serializers from rest_framework.exceptions import PermissionDenied -from bothub.api.v2.example.serializers import \ - RepositoryExampleEntitySerializer +from bothub.api.v2.example.serializers import RepositoryExampleEntitySerializer from bothub.api.v2.fields import TextField from bothub.api.v2.fields import EntityText -from bothub.api.v2.repository.validators import \ - CanContributeInRepositoryExampleValidator -from bothub.api.v2.repository.validators import \ - IntentAndSentenceNotExistsValidator -from bothub.api.v2.repository.validators import \ - ExampleWithIntentOrEntityValidator -from bothub.api.v2.repository.validators import \ - CanContributeInRepositoryValidator +from bothub.api.v2.repository.validators import ( + CanContributeInRepositoryExampleValidator, +) +from bothub.api.v2.repository.validators import IntentAndSentenceNotExistsValidator +from bothub.api.v2.repository.validators import ExampleWithIntentOrEntityValidator +from bothub.api.v2.repository.validators import CanContributeInRepositoryValidator from bothub.common import languages from bothub.common.models import Repository from bothub.common.models import RepositoryVote @@ -34,84 +31,75 @@ class RequestRepositoryAuthorizationSerializer(serializers.ModelSerializer): class Meta: model = RequestRepositoryAuthorization fields = [ - 'id', - 'user', - 'user__nickname', - 'repository', - 'text', - 'approved_by', - 'approved_by__nickname', - 'created_at', + "id", + "user", + "user__nickname", + "repository", + "text", + "approved_by", + "approved_by__nickname", + "created_at", ] ref_name = None repository = serializers.PrimaryKeyRelatedField( - queryset=Repository.objects, - style={'show': False}, - required=False) + queryset=Repository.objects, style={"show": False}, required=False + ) user = serializers.HiddenField( - default=serializers.CurrentUserDefault(), - style={'show': False}) + default=serializers.CurrentUserDefault(), style={"show": False} + ) text = TextField( - label=_('Leave a message for repository administrators'), + label=_("Leave a message for repository administrators"), min_length=5, - max_length=RequestRepositoryAuthorization._meta.get_field( - 'text').max_length, required=False) + max_length=RequestRepositoryAuthorization._meta.get_field("text").max_length, + required=False, + ) user__nickname = serializers.SlugRelatedField( - source='user', - slug_field='nickname', - read_only=True) + source="user", slug_field="nickname", read_only=True + ) approved_by__nickname = serializers.SlugRelatedField( - source='approved_by', - slug_field='nickname', - read_only=True) + source="approved_by", slug_field="nickname", read_only=True + ) approved_by = serializers.PrimaryKeyRelatedField( - read_only=True, - style={'show': False}) + read_only=True, style={"show": False} + ) def update(self, instance, validated_data): - validated_data.update({ - 'approved_by': self.context['request'].user, - }) + validated_data.update({"approved_by": self.context["request"].user}) return super().update(instance, validated_data) class RepositoryCategorySerializer(serializers.ModelSerializer): class Meta: model = RepositoryCategory - fields = [ - 'id', - 'name', - 'icon', - ] + fields = ["id", "name", "icon"] ref_name = None class RepositoryEntityLabelSerializer(serializers.ModelSerializer): class Meta: model = RepositoryEntityLabel - fields = [ - 'repository', - 'value', - 'entities', - 'examples__count', - ] + fields = ["repository", "value", "entities", "examples__count"] ref_name = None entities = serializers.SerializerMethodField() examples__count = serializers.SerializerMethodField() def get_entities(self, obj): - entities = obj.repository.other_entities \ - if obj.value == 'other' else obj.entities.all() + entities = ( + obj.repository.other_entities + if obj.value == "other" + else obj.entities.all() + ) return map(lambda e: e.value, entities) def get_examples__count(self, obj): - if obj.value == 'other': - return obj.repository.examples( - exclude_deleted=True).filter( - entities__entity__in=obj.repository.other_entities) \ - .count() + if obj.value == "other": + return ( + obj.repository.examples(exclude_deleted=True) + .filter(entities__entity__in=obj.repository.other_entities) + .count() + ) return obj.examples().count() @@ -124,109 +112,96 @@ class RepositoryAuthorizationSerializer(serializers.ModelSerializer): class Meta: model = RepositoryAuthorization fields = [ - 'uuid', - 'user', - 'user__nickname', - 'repository', - 'role', - 'level', - 'can_read', - 'can_contribute', - 'can_write', - 'is_admin', - 'created_at', - ] - read_only = [ - 'user', - 'user__nickname', - 'repository', - 'role', - 'created_at', + "uuid", + "user", + "user__nickname", + "repository", + "role", + "level", + "can_read", + "can_contribute", + "can_write", + "is_admin", + "created_at", ] + read_only = ["user", "user__nickname", "repository", "role", "created_at"] ref_name = None user__nickname = serializers.SlugRelatedField( - source='user', - slug_field='nickname', - read_only=True) + source="user", slug_field="nickname", read_only=True + ) class RepositorySerializer(serializers.ModelSerializer): class Meta: model = Repository fields = [ - 'uuid', - 'name', - 'slug', - 'description', - 'is_private', - 'available_languages', - 'entities', - 'entities_list', - 'labels_list', - 'ready_for_train', - 'created_at', - 'language', - 'owner', - 'owner__nickname', - 'categories', - 'categories_list', - 'intents', - 'intents_list', - 'labels', - 'other_label', - 'examples__count', - 'evaluate_languages_count', - 'absolute_url', - 'authorization', - 'ready_for_train', - 'requirements_to_train', - 'languages_ready_for_train', - 'request_authorization', - 'available_request_authorization', - 'languages_warnings', - 'algorithm', - 'use_language_model_featurizer', - 'use_competing_intents', - 'use_name_entities', - 'nlp_server', + "uuid", + "name", + "slug", + "description", + "is_private", + "available_languages", + "entities", + "entities_list", + "labels_list", + "ready_for_train", + "created_at", + "language", + "owner", + "owner__nickname", + "categories", + "categories_list", + "intents", + "intents_list", + "labels", + "other_label", + "examples__count", + "evaluate_languages_count", + "absolute_url", + "authorization", + "ready_for_train", + "requirements_to_train", + "languages_ready_for_train", + "request_authorization", + "available_request_authorization", + "languages_warnings", + "algorithm", + "use_language_model_featurizer", + "use_competing_intents", + "use_name_entities", + "nlp_server", ] read_only = [ - 'uuid', - 'available_languages', - 'entities', - 'entities_list', - 'evaluate_languages_count', - 'labels_list', - 'ready_for_train', - 'created_at', - 'authorization', - 'nlp_server', + "uuid", + "available_languages", + "entities", + "entities_list", + "evaluate_languages_count", + "labels_list", + "ready_for_train", + "created_at", + "authorization", + "nlp_server", ] ref_name = None language = serializers.ChoiceField( - LANGUAGE_CHOICES, - label=Repository._meta.get_field('language').verbose_name) + LANGUAGE_CHOICES, label=Repository._meta.get_field("language").verbose_name + ) owner = serializers.PrimaryKeyRelatedField(read_only=True) owner__nickname = serializers.SlugRelatedField( - source='owner', - slug_field='nickname', - read_only=True) + source="owner", slug_field="nickname", read_only=True + ) intents = serializers.SerializerMethodField() intents_list = serializers.SerializerMethodField() - categories = RepositoryCategorySerializer( - many=True, - read_only=True) + categories = RepositoryCategorySerializer(many=True, read_only=True) categories_list = serializers.SlugRelatedField( - source='categories', - slug_field='name', - many=True, - read_only=True) + source="categories", slug_field="name", many=True, read_only=True + ) labels = RepositoryEntityLabelSerializer( - source='current_labels', - many=True, - read_only=True) + source="current_labels", many=True, read_only=True + ) other_label = serializers.SerializerMethodField() examples__count = serializers.SerializerMethodField() evaluate_languages_count = serializers.SerializerMethodField() @@ -243,69 +218,70 @@ def get_nlp_server(self, obj): return settings.BOTHUB_NLP_BASE_URL def create(self, validated_data): - validated_data.update({ - 'owner': self.context['request'].user, - }) + validated_data.update({"owner": self.context["request"].user}) return super().create(validated_data) def get_entities(self, obj): - return obj.current_entities.values('value', 'id').distinct() + return obj.current_entities.values("value", "id").distinct() def get_intents(self, obj): return IntentSerializer( map( lambda intent: { - 'value': intent, - 'examples__count': obj.examples( - exclude_deleted=True).filter( - intent=intent).count(), + "value": intent, + "examples__count": obj.examples(exclude_deleted=True) + .filter(intent=intent) + .count(), }, - obj.intents), - many=True).data + obj.intents, + ), + many=True, + ).data def get_intents_list(self, obj): return obj.intents def get_other_label(self, obj): return RepositoryEntityLabelSerializer( - RepositoryEntityLabel( - repository=obj, - value='other')).data + RepositoryEntityLabel(repository=obj, value="other") + ).data def get_examples__count(self, obj): return obj.examples().count() def get_evaluate_languages_count(self, obj): - return dict(map( - lambda x: (x, obj.evaluations(language=x).count() - ), obj.available_languages - )) + return dict( + map( + lambda x: (x, obj.evaluations(language=x).count()), + obj.available_languages, + ) + ) def get_absolute_url(self, obj): return obj.get_absolute_url() def get_authorization(self, obj): - request = self.context.get('request') + request = self.context.get("request") if not request or not request.user.is_authenticated: return None return RepositoryAuthorizationSerializer( - obj.get_user_authorization(request.user)).data + obj.get_user_authorization(request.user) + ).data def get_request_authorization(self, obj): - request = self.context.get('request') + request = self.context.get("request") if not request or not request.user.is_authenticated: return None try: request_authorization = RequestRepositoryAuthorization.objects.get( - user=request.user, - repository=obj) - return RequestRepositoryAuthorizationSerializer( - request_authorization).data + user=request.user, repository=obj + ) + return RequestRepositoryAuthorizationSerializer(request_authorization).data except RequestRepositoryAuthorization.DoesNotExist: return None def get_available_request_authorization(self, obj): - request = self.context.get('request') + request = self.context.get("request") if not request or not request.user.is_authenticated: return False authorization = obj.get_user_authorization(request.user) @@ -315,8 +291,8 @@ def get_available_request_authorization(self, obj): return False try: RequestRepositoryAuthorization.objects.get( - user=request.user, - repository=obj) + user=request.user, repository=obj + ) return False except RequestRepositoryAuthorization.DoesNotExist: return True @@ -325,24 +301,16 @@ def get_available_request_authorization(self, obj): class RepositoryVotesSerializer(serializers.ModelSerializer): class Meta: model = RepositoryVote - fields = [ - 'user', - 'repository', - 'created', - ] + fields = ["user", "repository", "created"] - read_only_fields = [ - 'user', - 'created_at', - ] + read_only_fields = ["user", "created_at"] ref_name = None def create(self, validated_data): - user = self.context.get('request').user - repository = validated_data.pop('repository') + user = self.context.get("request").user + repository = validated_data.pop("repository") vote, created = RepositoryVote.objects.get_or_create( - repository=repository, - user=user + repository=repository, user=user ) return vote @@ -351,41 +319,34 @@ class ShortRepositorySerializer(serializers.ModelSerializer): class Meta: model = Repository fields = [ - 'uuid', - 'name', - 'slug', - 'description', - 'is_private', - 'categories', - 'categories_list', - 'language', - 'available_languages', - 'created_at', - 'owner', - 'owner__nickname', - 'absolute_url', - 'votes', + "uuid", + "name", + "slug", + "description", + "is_private", + "categories", + "categories_list", + "language", + "available_languages", + "created_at", + "owner", + "owner__nickname", + "absolute_url", + "votes", ] read_only = fields ref_name = None - categories = RepositoryCategorySerializer( - many=True, - read_only=True) + categories = RepositoryCategorySerializer(many=True, read_only=True) categories_list = serializers.SlugRelatedField( - source='categories', - slug_field='name', - many=True, - read_only=True) + source="categories", slug_field="name", many=True, read_only=True + ) owner__nickname = serializers.SlugRelatedField( - source='owner', - slug_field='nickname', - read_only=True) + source="owner", slug_field="nickname", read_only=True + ) absolute_url = serializers.SerializerMethodField() - votes = RepositoryVotesSerializer( - many=True, - read_only=True) + votes = RepositoryVotesSerializer(many=True, read_only=True) def get_absolute_url(self, obj): return obj.get_absolute_url() @@ -394,32 +355,21 @@ def get_absolute_url(self, obj): class RepositoryContributionsSerializer(serializers.ModelSerializer): class Meta: model = RepositoryAuthorization - fields = [ - 'user', - 'repository', - 'role', - 'created_at', - ] + fields = ["user", "repository", "role", "created_at"] - read_only_fields = [ - 'user', - 'role', - 'created_at', - ] + read_only_fields = ["user", "role", "created_at"] ref_name = None class RepositoryAuthorizationRoleSerializer(serializers.ModelSerializer): class Meta: model = RepositoryAuthorization - fields = [ - 'role', - ] + fields = ["role"] ref_name = None def validate(self, data): if self.instance.user == self.instance.repository.owner: - raise PermissionDenied(_('The owner role can\'t be changed.')) + raise PermissionDenied(_("The owner role can't be changed.")) return data @@ -427,22 +377,21 @@ class RepositoryTranslatedExampleEntitySeralizer(serializers.ModelSerializer): class Meta: model = RepositoryTranslatedExampleEntity fields = [ - 'id', - 'repository_translated_example', - 'start', - 'end', - 'entity', - 'created_at', - 'value', + "id", + "repository_translated_example", + "start", + "end", + "entity", + "created_at", + "value", ] ref_name = None repository_translated_example = serializers.PrimaryKeyRelatedField( queryset=RepositoryTranslatedExample.objects, - validators=[ - CanContributeInRepositoryTranslatedExampleValidator(), - ], - help_text='Example translation ID') + validators=[CanContributeInRepositoryTranslatedExampleValidator()], + help_text="Example translation ID", + ) entity = serializers.SerializerMethodField() value = serializers.SerializerMethodField() @@ -457,28 +406,25 @@ class RepositoryTranslatedExampleSerializer(serializers.ModelSerializer): class Meta: model = RepositoryTranslatedExample fields = [ - 'id', - 'original_example', - 'from_language', - 'language', - 'text', - 'has_valid_entities', - 'entities', - 'created_at', + "id", + "original_example", + "from_language", + "language", + "text", + "has_valid_entities", + "entities", + "created_at", ] ref_name = None original_example = serializers.PrimaryKeyRelatedField( queryset=RepositoryExample.objects, - validators=[ - CanContributeInRepositoryExampleValidator(), - ], - help_text=_('Example\'s ID')) + validators=[CanContributeInRepositoryExampleValidator()], + help_text=_("Example's ID"), + ) from_language = serializers.SerializerMethodField() has_valid_entities = serializers.SerializerMethodField() - entities = RepositoryTranslatedExampleEntitySeralizer( - many=True, - read_only=True) + entities = RepositoryTranslatedExampleEntitySeralizer(many=True, read_only=True) def get_from_language(self, obj): return obj.original_example.repository_update.language @@ -491,76 +437,63 @@ class RepositoryExampleSerializer(serializers.ModelSerializer): class Meta: model = RepositoryExample fields = [ - 'id', - 'repository', - 'repository_update', - 'deleted_in', - 'text', - 'intent', - 'language', - 'created_at', - 'entities', - 'translations', - ] - read_only_fields = [ - 'deleted_in', + "id", + "repository", + "repository_update", + "deleted_in", + "text", + "intent", + "language", + "created_at", + "entities", + "translations", ] + read_only_fields = ["deleted_in"] ref_name = None - id = serializers.PrimaryKeyRelatedField( - read_only=True, - style={'show': False}) - text = EntityText(style={'entities_field': 'entities'}, required=False) + id = serializers.PrimaryKeyRelatedField(read_only=True, style={"show": False}) + text = EntityText(style={"entities_field": "entities"}, required=False) repository = serializers.PrimaryKeyRelatedField( queryset=Repository.objects, - validators=[ - CanContributeInRepositoryValidator(), - ], + validators=[CanContributeInRepositoryValidator()], write_only=True, - style={'show': False}) + style={"show": False}, + ) repository_update = serializers.PrimaryKeyRelatedField( - read_only=True, - style={'show': False}, required=False) + read_only=True, style={"show": False}, required=False + ) language = serializers.ChoiceField( - languages.LANGUAGE_CHOICES, - allow_blank=True, - required=False) + languages.LANGUAGE_CHOICES, allow_blank=True, required=False + ) entities = RepositoryExampleEntitySerializer( - many=True, - style={'text_field': 'text'}, - required=False) - translations = RepositoryTranslatedExampleSerializer( - many=True, - read_only=True) + many=True, style={"text_field": "text"}, required=False + ) + translations = RepositoryTranslatedExampleSerializer(many=True, read_only=True) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - if kwargs['context'].get('request').stream is None: - self.fields['entities'] = \ - RepositoryExampleEntitySerializer( - many=True, - style={'text_field': 'text'}, - data='GET' - ) + if kwargs["context"].get("request").stream is None: + self.fields["entities"] = RepositoryExampleEntitySerializer( + many=True, style={"text_field": "text"}, data="GET" + ) self.validators.append(ExampleWithIntentOrEntityValidator()) self.validators.append(IntentAndSentenceNotExistsValidator()) def create(self, validated_data): - entities_data = validated_data.pop('entities') - repository = validated_data.pop('repository') + entities_data = validated_data.pop("entities") + repository = validated_data.pop("repository") try: - language = validated_data.pop('language') + language = validated_data.pop("language") except KeyError: language = None repository_update = repository.current_update(language or None) - validated_data.update({'repository_update': repository_update}) + validated_data.update({"repository_update": repository_update}) example = self.Meta.model.objects.create(**validated_data) for entity_data in entities_data: - entity_data.update({'repository_example': example.pk}) - entity_serializer = RepositoryExampleEntitySerializer( - data=entity_data) + entity_data.update({"repository_example": example.pk}) + entity_serializer = RepositoryExampleEntitySerializer(data=entity_data) entity_serializer.is_valid(raise_exception=True) entity_serializer.save() return example @@ -579,22 +512,21 @@ class RepositoryUpdateSerializer(serializers.ModelSerializer): class Meta: model = RepositoryUpdate fields = [ - 'id', - 'repository', - 'language', - 'created_at', - 'by', - 'by__nickname', - 'training_started_at', - 'trained_at', - 'failed_at', + "id", + "repository", + "language", + "created_at", + "by", + "by__nickname", + "training_started_at", + "trained_at", + "failed_at", ] ref_name = None by__nickname = serializers.SlugRelatedField( - source='by', - slug_field='nickname', - read_only=True) + source="by", slug_field="nickname", read_only=True + ) class RepositoryUpload(serializers.Serializer): diff --git a/bothub/api/v2/repository/validators.py b/bothub/api/v2/repository/validators.py index 56175af1..10de641c 100644 --- a/bothub/api/v2/repository/validators.py +++ b/bothub/api/v2/repository/validators.py @@ -8,69 +8,62 @@ class CanContributeInRepositoryExampleValidator(object): def __call__(self, value): repository = value.repository_update.repository - user_authorization = repository.get_user_authorization( - self.request.user) + user_authorization = repository.get_user_authorization(self.request.user) if not user_authorization.can_contribute: - raise PermissionDenied( - _('You can\'t contribute in this repository')) + raise PermissionDenied(_("You can't contribute in this repository")) def set_context(self, serializer): - self.request = serializer.context.get('request') + self.request = serializer.context.get("request") class CanContributeInRepositoryTranslatedExampleValidator(object): def __call__(self, value): repository = value.original_example.repository_update.repository - user_authorization = repository.get_user_authorization( - self.request.user) + user_authorization = repository.get_user_authorization(self.request.user) if not user_authorization.can_contribute: - raise PermissionDenied( - _('You can\'t contribute in this repository')) + raise PermissionDenied(_("You can't contribute in this repository")) def set_context(self, serializer): - self.request = serializer.context.get('request') + self.request = serializer.context.get("request") class CanContributeInRepositoryValidator(object): def __call__(self, value): - user_authorization = value.get_user_authorization( - self.request.user) + user_authorization = value.get_user_authorization(self.request.user) if not user_authorization.can_contribute: - raise PermissionDenied( - _('You can\'t contribute in this repository')) + raise PermissionDenied(_("You can't contribute in this repository")) def set_context(self, serializer): - self.request = serializer.context.get('request') + self.request = serializer.context.get("request") class ExampleWithIntentOrEntityValidator(object): def __call__(self, attrs): - intent = attrs.get('intent') - entities = attrs.get('entities') + intent = attrs.get("intent") + entities = attrs.get("entities") if not intent and not entities: - raise ValidationError(_('Define a intent or one entity')) + raise ValidationError(_("Define a intent or one entity")) class IntentAndSentenceNotExistsValidator(object): def __call__(self, attrs): - repository = attrs.get('repository') - intent = attrs.get('intent') - sentence = attrs.get('text') + repository = attrs.get("repository") + intent = attrs.get("intent") + sentence = attrs.get("text") if RepositoryExample.objects.filter( - text=sentence, - intent=intent, - repository_update__repository=repository + text=sentence, intent=intent, repository_update__repository=repository ).count(): - raise ValidationError(_('Intention and Sentence already exists')) + raise ValidationError(_("Intention and Sentence already exists")) class EntityNotEqualLabelValidator(object): def __call__(self, attrs): - entity = attrs.get('entity') - label = attrs.get('label') + entity = attrs.get("entity") + label = attrs.get("label") if entity == label: - raise ValidationError({'label': _( - 'Label name can\'t be equal to entity name')}) + raise ValidationError( + {"label": _("Label name can't be equal to entity name")} + ) diff --git a/bothub/api/v2/repository/views.py b/bothub/api/v2/repository/views.py index 4214cba7..ad016349 100644 --- a/bothub/api/v2/repository/views.py +++ b/bothub/api/v2/repository/views.py @@ -56,29 +56,29 @@ class RepositoryViewSet( - mixins.CreateModelMixin, - mixins.RetrieveModelMixin, - mixins.UpdateModelMixin, - mixins.DestroyModelMixin, - GenericViewSet): + mixins.CreateModelMixin, + mixins.RetrieveModelMixin, + mixins.UpdateModelMixin, + mixins.DestroyModelMixin, + GenericViewSet, +): """ Manager repository (bot). """ + queryset = Repository.objects - lookup_field = 'uuid' - lookup_fields = ['uuid'] + lookup_field = "uuid" + lookup_fields = ["uuid"] serializer_class = RepositorySerializer - permission_classes = [ - IsAuthenticatedOrReadOnly, - RepositoryPermission, - ] + permission_classes = [IsAuthenticatedOrReadOnly, RepositoryPermission] metadata_class = Metadata @action( detail=True, - methods=['GET'], - url_name='repository-languages-status', - lookup_fields=['uuid']) + methods=["GET"], + url_name="repository-languages-status", + lookup_fields=["uuid"], + ) def languagesstatus(self, request, **kwargs): """ Get current language status. @@ -87,15 +87,14 @@ def languagesstatus(self, request, **kwargs): return Response(status=405) repository = self.get_object() - return Response({ - 'languages_status': repository.languages_status, - }) + return Response({"languages_status": repository.languages_status}) @action( detail=True, - methods=['GET'], - url_name='repository-train', - lookup_fields=['uuid']) + methods=["GET"], + url_name="repository-train", + lookup_fields=["uuid"], + ) def train(self, request, **kwargs): """ Train current update using Bothub NLP service @@ -106,29 +105,28 @@ def train(self, request, **kwargs): user_authorization = repository.get_user_authorization(request.user) if not user_authorization.can_write: raise PermissionDenied() - request = repository.request_nlp_train( # pragma: no cover - user_authorization) + request = repository.request_nlp_train(user_authorization) # pragma: no cover if request.status_code != status.HTTP_200_OK: # pragma: no cover raise APIException( # pragma: no cover - {'status_code': request.status_code}, - code=request.status_code) + {"status_code": request.status_code}, code=request.status_code + ) return Response(request.json()) # pragma: no cover @action( detail=True, - methods=['POST'], - url_name='repository-analyze', + methods=["POST"], + url_name="repository-analyze", permission_classes=[], - lookup_fields=['uuid']) + lookup_fields=["uuid"], + ) def analyze(self, request, **kwargs): repository = self.get_object() user_authorization = repository.get_user_authorization(request.user) - serializer = AnalyzeTextSerializer( - data=request.data) # pragma: no cover + serializer = AnalyzeTextSerializer(data=request.data) # pragma: no cover serializer.is_valid(raise_exception=True) # pragma: no cover request = repository.request_nlp_analyze( - user_authorization, - serializer.data) # pragma: no cover + user_authorization, serializer.data + ) # pragma: no cover if request.status_code == status.HTTP_200_OK: # pragma: no cover return Response(request.json()) # pragma: no cover @@ -141,17 +139,20 @@ def analyze(self, request, **kwargs): if not response: # pragma: no cover raise APIException( # pragma: no cover - detail=_('Something unexpected happened! ' + \ - 'We couldn\'t analyze your text.')) - error = response.get('error') # pragma: no cover - message = error.get('message') # pragma: no cover + detail=_( + "Something unexpected happened! " + "We couldn't analyze your text." + ) + ) + error = response.get("error") # pragma: no cover + message = error.get("message") # pragma: no cover raise APIException(detail=message) # pragma: no cover @action( detail=True, - methods=['POST'], - url_name='repository-evaluate', - lookup_fields=['uuid']) + methods=["POST"], + url_name="repository-evaluate", + lookup_fields=["uuid"], + ) def evaluate(self, request, **kwargs): """ Evaluate repository using Bothub NLP service @@ -160,198 +161,170 @@ def evaluate(self, request, **kwargs): user_authorization = repository.get_user_authorization(request.user) if not user_authorization.can_write: raise PermissionDenied() - serializer = EvaluateSerializer( - data=request.data) # pragma: no cover + serializer = EvaluateSerializer(data=request.data) # pragma: no cover serializer.is_valid(raise_exception=True) # pragma: no cover - if not repository.evaluations( - language=request.data.get('language') - ).count(): + if not repository.evaluations(language=request.data.get("language")).count(): raise APIException( - detail=_('You need to have at least ' + - 'one registered test phrase')) # pragma: no cover + detail=_("You need to have at least " + "one registered test phrase") + ) # pragma: no cover if len(repository.intents) <= 1: raise APIException( - detail=_('You need to have at least ' + - 'two registered intents')) # pragma: no cover + detail=_("You need to have at least " + "two registered intents") + ) # pragma: no cover request = repository.request_nlp_evaluate( # pragma: no cover - user_authorization, serializer.data) + user_authorization, serializer.data + ) if request.status_code != status.HTTP_200_OK: # pragma: no cover raise APIException( # pragma: no cover - {'status_code': request.status_code}, - code=request.status_code) + {"status_code": request.status_code}, code=request.status_code + ) return Response(request.json()) # pragma: no cover @method_decorator( - name='list', + name="list", decorator=swagger_auto_schema( manual_parameters=[ openapi.Parameter( - 'user', + "user", openapi.IN_QUERY, - description='Nickname User to find repositories votes', - type=openapi.TYPE_STRING + description="Nickname User to find repositories votes", + type=openapi.TYPE_STRING, ), openapi.Parameter( - 'repository', + "repository", openapi.IN_QUERY, - description='Repository UUID, returns a list of ' - 'users who voted for this repository', - type=openapi.TYPE_STRING + description="Repository UUID, returns a list of " + "users who voted for this repository", + type=openapi.TYPE_STRING, ), ] - ) + ), ) class RepositoryVotesViewSet( - mixins.CreateModelMixin, - mixins.DestroyModelMixin, - mixins.ListModelMixin, - GenericViewSet): + mixins.CreateModelMixin, + mixins.DestroyModelMixin, + mixins.ListModelMixin, + GenericViewSet, +): """ Manager repository votes (bot). """ + queryset = RepositoryVote.objects.all() - lookup_field = 'repository' - lookup_fields = ['repository'] + lookup_field = "repository" + lookup_fields = ["repository"] serializer_class = RepositoryVotesSerializer - permission_classes = [ - IsAuthenticatedOrReadOnly - ] + permission_classes = [IsAuthenticatedOrReadOnly] metadata_class = Metadata def get_queryset(self, *args, **kwargs): - if self.request.query_params.get('repository', None): + if self.request.query_params.get("repository", None): return self.queryset.filter( - repository=self.request.query_params.get( - 'repository', - None - ) + repository=self.request.query_params.get("repository", None) ) - elif self.request.query_params.get('user', None): + elif self.request.query_params.get("user", None): return self.queryset.filter( - user__nickname=self.request.query_params.get( - 'user', - None - ) + user__nickname=self.request.query_params.get("user", None) ) else: return self.queryset.all() def destroy(self, request, *args, **kwargs): self.queryset.filter( - repository=self.request.query_params.get( - 'repository', - None - ), - user=self.request.user + repository=self.request.query_params.get("repository", None), + user=self.request.user, ).delete() return Response(status=status.HTTP_204_NO_CONTENT) -class RepositoriesViewSet( - mixins.ListModelMixin, - GenericViewSet): +class RepositoriesViewSet(mixins.ListModelMixin, GenericViewSet): """ List all public repositories. """ + serializer_class = ShortRepositorySerializer queryset = Repository.objects.all().publics().order_by_relevance() filter_class = RepositoriesFilter - filter_backends = [ - DjangoFilterBackend, - SearchFilter, - ] - search_fields = [ - '$name', - '^name', - '=name', - ] + filter_backends = [DjangoFilterBackend, SearchFilter] + search_fields = ["$name", "^name", "=name"] @method_decorator( - name='list', + name="list", decorator=swagger_auto_schema( manual_parameters=[ openapi.Parameter( - 'nickname', + "nickname", openapi.IN_QUERY, - description='Nickname User', + description="Nickname User", type=openapi.TYPE_STRING, - required=True - ), + required=True, + ) ] - ) + ), ) -class RepositoriesContributionsViewSet( - mixins.ListModelMixin, - GenericViewSet): +class RepositoriesContributionsViewSet(mixins.ListModelMixin, GenericViewSet): """ List Repositories Contributions by user. """ + serializer_class = RepositoryContributionsSerializer queryset = RepositoryAuthorization.objects.all() - permission_classes = [ - IsAuthenticatedOrReadOnly - ] - lookup_field = 'nickname' + permission_classes = [IsAuthenticatedOrReadOnly] + lookup_field = "nickname" def get_queryset(self): - if self.request.query_params.get('nickname', None): + if self.request.query_params.get("nickname", None): return self.queryset.filter( - user__nickname=self.request.query_params.get( - 'nickname', - None - ) + user__nickname=self.request.query_params.get("nickname", None) ) else: return self.queryset.none() -class RepositoryCategoriesView( - mixins.ListModelMixin, - GenericViewSet): +class RepositoryCategoriesView(mixins.ListModelMixin, GenericViewSet): """ List all categories. """ + serializer_class = RepositoryCategorySerializer queryset = RepositoryCategory.objects.all() pagination_class = None @method_decorator( - name='list', + name="list", decorator=swagger_auto_schema( manual_parameters=[ openapi.Parameter( - 'nickname', + "nickname", openapi.IN_QUERY, - description='Nickname User to find repositories', - type=openapi.TYPE_STRING - ), + description="Nickname User to find repositories", + type=openapi.TYPE_STRING, + ) ] - ) + ), ) -class SearchRepositoriesViewSet( - mixins.ListModelMixin, - GenericViewSet): +class SearchRepositoriesViewSet(mixins.ListModelMixin, GenericViewSet): """ List all user's repositories """ + queryset = Repository.objects serializer_class = RepositorySerializer - lookup_field = 'nickname' + lookup_field = "nickname" def get_queryset(self, *args, **kwargs): try: - if self.request.query_params.get('nickname', None): + if self.request.query_params.get("nickname", None): return self.queryset.filter( owner__nickname=self.request.query_params.get( - 'nickname', - self.request.user + "nickname", self.request.user ) ) else: @@ -361,22 +334,22 @@ def get_queryset(self, *args, **kwargs): class RepositoryAuthorizationViewSet( - MultipleFieldLookupMixin, - mixins.UpdateModelMixin, - mixins.ListModelMixin, - GenericViewSet): + MultipleFieldLookupMixin, + mixins.UpdateModelMixin, + mixins.ListModelMixin, + GenericViewSet, +): queryset = RepositoryAuthorization.objects.exclude( - role=RepositoryAuthorization.ROLE_NOT_SETTED) + role=RepositoryAuthorization.ROLE_NOT_SETTED + ) serializer_class = RepositoryAuthorizationSerializer filter_class = RepositoryAuthorizationFilter - lookup_fields = ['repository__uuid', 'user__nickname'] - permission_classes = [ - IsAuthenticated, - ] + lookup_fields = ["repository__uuid", "user__nickname"] + permission_classes = [IsAuthenticated] def get_object(self): - repository_uuid = self.kwargs.get('repository__uuid') - user_nickname = self.kwargs.get('user__nickname') + repository_uuid = self.kwargs.get("repository__uuid") + user_nickname = self.kwargs.get("user__nickname") repository = get_object_or_404(Repository, uuid=repository_uuid) user = get_object_or_404(User, nickname=user_nickname) @@ -387,14 +360,11 @@ def get_object(self): return obj def update(self, *args, **kwargs): - self.lookup_field = 'user__nickname' + self.lookup_field = "user__nickname" self.filter_class = None self.serializer_class = RepositoryAuthorizationRoleSerializer - self.permission_classes = [ - IsAuthenticated, - RepositoryAdminManagerAuthorization, - ] + self.permission_classes = [IsAuthenticated, RepositoryAdminManagerAuthorization] response = super().update(*args, **kwargs) instance = self.get_object() if instance.role is not RepositoryAuthorization.ROLE_NOT_SETTED: @@ -407,21 +377,20 @@ def list(self, request, *args, **kwargs): class RepositoryAuthorizationRequestsViewSet( - mixins.ListModelMixin, - mixins.CreateModelMixin, - mixins.UpdateModelMixin, - mixins.DestroyModelMixin, - GenericViewSet): + mixins.ListModelMixin, + mixins.CreateModelMixin, + mixins.UpdateModelMixin, + mixins.DestroyModelMixin, + GenericViewSet, +): """ List of all authorization requests for a repository """ - queryset = RequestRepositoryAuthorization.objects.exclude( - approved_by__isnull=False) + + queryset = RequestRepositoryAuthorization.objects.exclude(approved_by__isnull=False) serializer_class = RequestRepositoryAuthorizationSerializer filter_class = RepositoryAuthorizationRequestsFilter - permission_classes = [ - IsAuthenticated, - ] + permission_classes = [IsAuthenticated] def create(self, request, *args, **kwargs): self.queryset = RequestRepositoryAuthorization.objects @@ -431,10 +400,7 @@ def create(self, request, *args, **kwargs): def update(self, request, *args, **kwargs): self.queryset = RequestRepositoryAuthorization.objects self.filter_class = None - self.permission_classes = [ - IsAuthenticated, - RepositoryAdminManagerAuthorization, - ] + self.permission_classes = [IsAuthenticated, RepositoryAdminManagerAuthorization] try: return super().update(request, *args, **kwargs) except DjangoValidationError as e: @@ -443,19 +409,17 @@ def update(self, request, *args, **kwargs): def destroy(self, request, *args, **kwargs): self.queryset = RequestRepositoryAuthorization.objects self.filter_class = None - self.permission_classes = [ - IsAuthenticated, - RepositoryAdminManagerAuthorization, - ] + self.permission_classes = [IsAuthenticated, RepositoryAdminManagerAuthorization] return super().destroy(request, *args, **kwargs) class RepositoryExampleViewSet( - mixins.CreateModelMixin, - mixins.RetrieveModelMixin, - mixins.DestroyModelMixin, - mixins.UpdateModelMixin, - GenericViewSet): + mixins.CreateModelMixin, + mixins.RetrieveModelMixin, + mixins.DestroyModelMixin, + mixins.UpdateModelMixin, + GenericViewSet, +): """ Manager repository example. @@ -469,11 +433,10 @@ class RepositoryExampleViewSet( Update repository example. """ + queryset = RepositoryExample.objects serializer_class = RepositoryExampleSerializer - permission_classes = [ - RepositoryExamplePermission, - ] + permission_classes = [RepositoryExamplePermission] def create(self, request, *args, **kwargs): self.permission_classes = [permissions.IsAuthenticated] @@ -481,15 +444,15 @@ def create(self, request, *args, **kwargs): @action( detail=True, - methods=['POST'], - url_name='repository-upload-examples', + methods=["POST"], + url_name="repository-upload-examples", parser_classes=[parsers.MultiPartParser], - serializer_class=RepositoryUpload) + serializer_class=RepositoryUpload, + ) def upload_examples(self, request, **kwargs): try: repository = get_object_or_404( - Repository, - pk=request.data.get('repository') + Repository, pk=request.data.get("repository") ) except DjangoValidationError: raise PermissionDenied() @@ -498,21 +461,20 @@ def upload_examples(self, request, **kwargs): if not user_authorization.can_write: raise PermissionDenied() - f = request.FILES.get('file') + f = request.FILES.get("file") try: json_data = json.loads(f.read().decode()) except json.decoder.JSONDecodeError: - raise UnsupportedMediaType('json') + raise UnsupportedMediaType("json") count_added = 0 not_added = [] for data in json_data: response_data = data - response_data['repository'] = request.data.get('repository') + response_data["repository"] = request.data.get("repository") serializer = RepositoryExampleSerializer( - data=response_data, - context={'request': request} + data=response_data, context={"request": request} ) if serializer.is_valid(): serializer.save() @@ -520,25 +482,18 @@ def upload_examples(self, request, **kwargs): else: not_added.append(data) - return Response({ - 'added': count_added, - 'not_added': not_added - }) + return Response({"added": count_added, "not_added": not_added}) def perform_destroy(self, obj): if obj.deleted_in: - raise APIException(_('Example already deleted')) + raise APIException(_("Example already deleted")) obj.delete() -class RepositoryUpdatesViewSet( - mixins.ListModelMixin, - GenericViewSet): +class RepositoryUpdatesViewSet(mixins.ListModelMixin, GenericViewSet): queryset = RepositoryUpdate.objects.filter( - training_started_at__isnull=False).order_by('-trained_at') + training_started_at__isnull=False + ).order_by("-trained_at") serializer_class = RepositoryUpdateSerializer filter_class = RepositoryUpdatesFilter - permission_classes = [ - IsAuthenticated, - RepositoryUpdateHasPermission, - ] + permission_classes = [IsAuthenticated, RepositoryUpdateHasPermission] diff --git a/bothub/api/v2/routers.py b/bothub/api/v2/routers.py index 5f45520b..b7881f5a 100644 --- a/bothub/api/v2/routers.py +++ b/bothub/api/v2/routers.py @@ -35,16 +35,16 @@ class Router(routers.SimpleRouter): # Generated using @action decorator # on methods of the viewset. routers.DynamicRoute( - url=r'^{prefix}/{url_path}{trailing_slash}$', - name='{basename}-{url_name}', + url=r"^{prefix}/{url_path}{trailing_slash}$", + name="{basename}-{url_name}", detail=True, initkwargs={}, ), # Dynamically generated detail routes. # Generated using @action decorator on methods of the viewset. routers.DynamicRoute( - url=r'^{prefix}/{lookup}/{url_path}{trailing_slash}$', - name='{basename}-{url_name}', + url=r"^{prefix}/{lookup}/{url_path}{trailing_slash}$", + name="{basename}-{url_name}", detail=True, initkwargs={}, ), @@ -52,101 +52,93 @@ class Router(routers.SimpleRouter): def get_routes(self, viewset): ret = super().get_routes(viewset) - lookup_field = getattr(viewset, 'lookup_field', None) + lookup_field = getattr(viewset, "lookup_field", None) if lookup_field: # List route. - ret.append(routers.Route( - url=r'^{prefix}{trailing_slash}$', - mapping={ - 'get': 'list', - 'post': 'create' - }, - name='{basename}-list', - detail=False, - initkwargs={'suffix': 'List'}, - )) + ret.append( + routers.Route( + url=r"^{prefix}{trailing_slash}$", + mapping={"get": "list", "post": "create"}, + name="{basename}-list", + detail=False, + initkwargs={"suffix": "List"}, + ) + ) - detail_url_regex = r'^{prefix}/{lookup}{trailing_slash}$' + detail_url_regex = r"^{prefix}/{lookup}{trailing_slash}$" if not lookup_field: - detail_url_regex = r'^{prefix}{trailing_slash}$' + detail_url_regex = r"^{prefix}{trailing_slash}$" # Detail route. - ret.append(routers.Route( - url=detail_url_regex, - mapping={ - 'get': 'retrieve', - 'put': 'update', - 'patch': 'partial_update', - 'delete': 'destroy' - }, - name='{basename}-detail', - detail=True, - initkwargs={'suffix': 'Instance'} - )) + ret.append( + routers.Route( + url=detail_url_regex, + mapping={ + "get": "retrieve", + "put": "update", + "patch": "partial_update", + "delete": "destroy", + }, + name="{basename}-detail", + detail=True, + initkwargs={"suffix": "Instance"}, + ) + ) return ret - def get_lookup_regex(self, viewset, lookup_prefix=''): - lookup_fields = getattr(viewset, 'lookup_fields', None) + def get_lookup_regex(self, viewset, lookup_prefix=""): + lookup_fields = getattr(viewset, "lookup_fields", None) if lookup_fields: - base_regex = '(?P<{lookup_prefix}{lookup_url_kwarg}>[^/.]+)' - return '/'.join(map( - lambda x: base_regex.format( - lookup_prefix=lookup_prefix, - lookup_url_kwarg=x), - lookup_fields)) + base_regex = "(?P<{lookup_prefix}{lookup_url_kwarg}>[^/.]+)" + return "/".join( + map( + lambda x: base_regex.format( + lookup_prefix=lookup_prefix, lookup_url_kwarg=x + ), + lookup_fields, + ) + ) return super().get_lookup_regex(viewset, lookup_prefix) router = Router() -router.register('repository/repository-info', RepositoryViewSet) -router.register('repository/repository-votes', RepositoryVotesViewSet) -router.register('repository/repositories', RepositoriesViewSet) -router.register( - 'repository/repositories-contributions', - RepositoriesContributionsViewSet -) -router.register('repository/categories', RepositoryCategoriesView) -router.register('repository/examples', ExamplesViewSet) -router.register('repository/search-repositories', SearchRepositoriesViewSet) -router.register('repository/authorizations', RepositoryAuthorizationViewSet) -router.register( - 'repository/authorization-requests', - RepositoryAuthorizationRequestsViewSet -) -router.register('repository/example', RepositoryExampleViewSet) -router.register('repository/evaluate/results', ResultsListViewSet) -router.register('repository/evaluate', EvaluateViewSet) -router.register('repository/translation', RepositoryTranslatedExampleViewSet) -router.register('repository/updates', RepositoryUpdatesViewSet) +router.register("repository/repository-info", RepositoryViewSet) +router.register("repository/repository-votes", RepositoryVotesViewSet) +router.register("repository/repositories", RepositoriesViewSet) router.register( - 'repository/nlp/authorization/train', - RepositoryAuthorizationTrainViewSet + "repository/repositories-contributions", RepositoriesContributionsViewSet ) +router.register("repository/categories", RepositoryCategoriesView) +router.register("repository/examples", ExamplesViewSet) +router.register("repository/search-repositories", SearchRepositoriesViewSet) +router.register("repository/authorizations", RepositoryAuthorizationViewSet) router.register( - 'repository/nlp/authorization/parse', - RepositoryAuthorizationParseViewSet + "repository/authorization-requests", RepositoryAuthorizationRequestsViewSet ) +router.register("repository/example", RepositoryExampleViewSet) +router.register("repository/evaluate/results", ResultsListViewSet) +router.register("repository/evaluate", EvaluateViewSet) +router.register("repository/translation", RepositoryTranslatedExampleViewSet) +router.register("repository/updates", RepositoryUpdatesViewSet) router.register( - 'repository/nlp/authorization/info', - RepositoryAuthorizationInfoViewSet + "repository/nlp/authorization/train", RepositoryAuthorizationTrainViewSet ) router.register( - 'repository/nlp/authorization/evaluate', - RepositoryAuthorizationEvaluateViewSet + "repository/nlp/authorization/parse", RepositoryAuthorizationParseViewSet ) +router.register("repository/nlp/authorization/info", RepositoryAuthorizationInfoViewSet) router.register( - 'repository/nlp/authorization/langs', - NLPLangsViewSet + "repository/nlp/authorization/evaluate", RepositoryAuthorizationEvaluateViewSet ) +router.register("repository/nlp/authorization/langs", NLPLangsViewSet) router.register( - 'repository/nlp/update_interpreters', - RepositoryUpdateInterpretersViewSet + "repository/nlp/update_interpreters", RepositoryUpdateInterpretersViewSet ) -router.register('account/login', LoginViewSet) -router.register('account/register', RegisterUserViewSet) -router.register('account/change-password', ChangePasswordViewSet) -router.register('account/forgot-password', RequestResetPasswordViewSet) -router.register('account/user-profile', UserProfileViewSet) -router.register('account/search-user', SearchUserViewSet) -router.register('account/reset-password', ResetPasswordViewSet) +router.register("account/login", LoginViewSet) +router.register("account/register", RegisterUserViewSet) +router.register("account/change-password", ChangePasswordViewSet) +router.register("account/forgot-password", RequestResetPasswordViewSet) +router.register("account/user-profile", UserProfileViewSet) +router.register("account/search-user", SearchUserViewSet) +router.register("account/reset-password", ResetPasswordViewSet) diff --git a/bothub/api/v2/tests/test_account.py b/bothub/api/v2/tests/test_account.py index aabfa3fe..582c35de 100644 --- a/bothub/api/v2/tests/test_account.py +++ b/bothub/api/v2/tests/test_account.py @@ -21,46 +21,32 @@ class LoginTestCase(TestCase): def setUp(self): self.factory = RequestFactory() - self.password = 'abcgq!!123' - self.email = 'user@user.com' + self.password = "abcgq!!123" + self.email = "user@user.com" - user = User.objects.create( - email=self.email, - nickname='user', - name='User') + user = User.objects.create(email=self.email, nickname="user", name="User") user.set_password(self.password) - user.save(update_fields=['password']) + user.save(update_fields=["password"]) def request(self, data): - request = self.factory.post( - '/v2/account/login/', - data) - response = LoginViewSet.as_view( - {'post': 'create'})(request) + request = self.factory.post("/v2/account/login/", data) + response = LoginViewSet.as_view({"post": "create"})(request) response.render() content_data = json.loads(response.content) - return (response, content_data,) + return (response, content_data) def test_okay(self): - response, content_data = self.request({ - 'username': self.email, - 'password': self.password, - }) - self.assertEqual( - response.status_code, - status.HTTP_201_CREATED) - self.assertIn( - 'token', - content_data.keys()) + response, content_data = self.request( + {"username": self.email, "password": self.password} + ) + self.assertEqual(response.status_code, status.HTTP_201_CREATED) + self.assertIn("token", content_data.keys()) def test_wrong_password(self): - response, content_data = self.request({ - 'username': self.email, - 'password': 'wrong', - }) - self.assertEqual( - response.status_code, - status.HTTP_400_BAD_REQUEST) + response, content_data = self.request( + {"username": self.email, "password": "wrong"} + ) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) class RegisterUserTestCase(TestCase): @@ -68,119 +54,87 @@ def setUp(self): self.factory = RequestFactory() def request(self, data): - request = self.factory.post( - '/v2/account/register/', - data) - response = RegisterUserViewSet.as_view( - {'post': 'create'})(request) + request = self.factory.post("/v2/account/register/", data) + response = RegisterUserViewSet.as_view({"post": "create"})(request) response.render() content_data = json.loads(response.content) - return (response, content_data,) + return (response, content_data) def test_okay(self): - email = 'fake@user.com' - password = 'abc!1234' - response, content_data = self.request({ - 'email': email, - 'name': 'Fake', - 'nickname': 'fake', - 'password': password, - }) - self.assertEqual( - response.status_code, - status.HTTP_201_CREATED) + email = "fake@user.com" + password = "abc!1234" + response, content_data = self.request( + {"email": email, "name": "Fake", "nickname": "fake", "password": password} + ) + self.assertEqual(response.status_code, status.HTTP_201_CREATED) user = User.objects.get(email=email) self.assertTrue(user.check_password(password)) def test_invalid_password(self): - response, content_data = self.request({ - 'email': 'fake@user.com', - 'name': 'Fake', - 'nickname': 'fake', - 'password': 'abc', - }) - self.assertEqual( - response.status_code, - status.HTTP_400_BAD_REQUEST) - self.assertIn( - 'password', - content_data.keys()) + response, content_data = self.request( + { + "email": "fake@user.com", + "name": "Fake", + "nickname": "fake", + "password": "abc", + } + ) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + self.assertIn("password", content_data.keys()) def test_unique_nickname(self): - nickname = 'fake' - User.objects.create_user('user1@user.com', nickname) - response, content_data = self.request({ - 'email': 'user2@user.com', - 'name': 'Fake', - 'nickname': nickname, - 'password': 'abc!1234', - }) - self.assertEqual( - response.status_code, - status.HTTP_400_BAD_REQUEST) - self.assertIn( - 'nickname', - content_data.keys()) + nickname = "fake" + User.objects.create_user("user1@user.com", nickname) + response, content_data = self.request( + { + "email": "user2@user.com", + "name": "Fake", + "nickname": nickname, + "password": "abc!1234", + } + ) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + self.assertIn("nickname", content_data.keys()) def test_invalid_nickname_url_conflict(self): - URL_PATHS = [ - 'api', - 'docs', - 'admin', - ] + URL_PATHS = ["api", "docs", "admin"] for url_path in URL_PATHS: - response, content_data = self.request({ - 'email': '{}@fake.com'.format(url_path), - 'name': 'Fake', - 'nickname': url_path, - 'password': 'abc!1234', - }) + response, content_data = self.request( + { + "email": "{}@fake.com".format(url_path), + "name": "Fake", + "nickname": url_path, + "password": "abc!1234", + } + ) - self.assertEqual( - response.status_code, - status.HTTP_400_BAD_REQUEST) - self.assertIn( - 'nickname', - content_data.keys()) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + self.assertIn("nickname", content_data.keys()) class RequestResetPasswordTestCase(TestCase): def setUp(self): self.factory = RequestFactory() - self.email = 'user@user.com' + self.email = "user@user.com" - User.objects.create( - email=self.email, - nickname='user', - name='User') + User.objects.create(email=self.email, nickname="user", name="User") def request(self, data): - request = self.factory.post( - '/v2/account/forgot-password/', - data) - response = RequestResetPasswordViewSet.as_view( - {'post': 'create'})(request) + request = self.factory.post("/v2/account/forgot-password/", data) + response = RequestResetPasswordViewSet.as_view({"post": "create"})(request) response.render() - content_data = json.loads(response.content or 'null') - return (response, content_data,) + content_data = json.loads(response.content or "null") + return (response, content_data) def test_okay(self): - response, content_data = self.request({ - 'email': self.email, - }) + response, content_data = self.request({"email": self.email}) def test_email_not_found(self): - response, content_data = self.request({ - 'email': 'nouser@fake.com', - }) - self.assertEqual( - response.status_code, - status.HTTP_400_BAD_REQUEST) - self.assertIn( - 'email', - content_data.keys()) + response, content_data = self.request({"email": "nouser@fake.com"}) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + self.assertIn("email", content_data.keys()) class ResetPasswordTestCase(TestCase): @@ -188,97 +142,72 @@ def setUp(self): self.factory = RequestFactory() self.user = User.objects.create( - email='user@user.com', - nickname='user', - name='User') + email="user@user.com", nickname="user", name="User" + ) self.reset_password_token = self.user.make_password_reset_token() def request(self, nickname, data): request = self.factory.post( - '/v2/account/reset-password/{}/'.format(nickname), - data) - response = ResetPasswordViewSet.as_view( - {'post': 'update'})(request, nickname=nickname) + "/v2/account/reset-password/{}/".format(nickname), data + ) + response = ResetPasswordViewSet.as_view({"post": "update"})( + request, nickname=nickname + ) response.render() - content_data = json.loads(response.content or 'null') - return (response, content_data,) + content_data = json.loads(response.content or "null") + return (response, content_data) def test_okay(self): - new_password = 'valid12!' + new_password = "valid12!" response, content_data = self.request( self.user.nickname, - { - 'token': self.reset_password_token, - 'password': new_password, - }) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) + {"token": self.reset_password_token, "password": new_password}, + ) + self.assertEqual(response.status_code, status.HTTP_200_OK) self.user = User.objects.get(pk=self.user.pk) self.assertTrue(self.user.check_password(new_password)) def test_invalid_token(self): response, content_data = self.request( - self.user.nickname, - { - 'token': '112233', - 'password': 'valid12!', - }) - self.assertEqual( - response.status_code, - status.HTTP_400_BAD_REQUEST) - self.assertIn( - 'token', - content_data.keys()) + self.user.nickname, {"token": "112233", "password": "valid12!"} + ) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + self.assertIn("token", content_data.keys()) class ChangePasswordTestCase(TestCase): def setUp(self): self.factory = RequestFactory() self.user, self.user_token = create_user_and_token() - self.password = '12555q!66' + self.password = "12555q!66" self.user.set_password(self.password) - self.user.save(update_fields=['password']) + self.user.save(update_fields=["password"]) def request(self, data, token): - authorization_header = { - 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), - } + authorization_header = {"HTTP_AUTHORIZATION": "Token {}".format(token.key)} request = self.factory.post( - '/v2/account/change-password/', - data, - **authorization_header) - response = ChangePasswordViewSet.as_view( - {'post': 'update'})(request) + "/v2/account/change-password/", data, **authorization_header + ) + response = ChangePasswordViewSet.as_view({"post": "update"})(request) response.render() - content_data = json.loads(response.content or 'null') - return (response, content_data,) + content_data = json.loads(response.content or "null") + return (response, content_data) def test_okay(self): - new_password = 'kkl8&!qq' + new_password = "kkl8&!qq" response, content_data = self.request( - { - 'current_password': self.password, - 'password': new_password, - }, - self.user_token) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) + {"current_password": self.password, "password": new_password}, + self.user_token, + ) + self.assertEqual(response.status_code, status.HTTP_200_OK) def test_wrong_password(self): response, content_data = self.request( - { - 'current_password': 'wrong_password', - 'password': 'new_password', - }, - self.user_token) - self.assertEqual( - response.status_code, - status.HTTP_400_BAD_REQUEST) - self.assertIn( - 'current_password', - content_data.keys()) + {"current_password": "wrong_password", "password": "new_password"}, + self.user_token, + ) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + self.assertIn("current_password", content_data.keys()) class ListUserProfileTestCase(TestCase): @@ -287,35 +216,23 @@ def setUp(self): self.user, self.user_token = create_user_and_token() def request(self, token, nickname): - request = self.factory.get( - '/v2/account/user-profile/{}/'.format(nickname) + request = self.factory.get("/v2/account/user-profile/{}/".format(nickname)) + response = UserProfileViewSet.as_view({"get": "retrieve"})( + request, nickname=nickname ) - response = UserProfileViewSet.as_view( - {'get': 'retrieve'})(request, nickname=nickname) response.render() content_data = json.loads(response.content) - return (response, content_data,) + return (response, content_data) def test_okay(self): - response, content_data = self.request( - self.user_token, - self.user.nickname - ) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) - self.assertEqual( - content_data.get('nickname'), - self.user.nickname) + response, content_data = self.request(self.user_token, self.user.nickname) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(content_data.get("nickname"), self.user.nickname) def test_not_exists(self): - response, content_data = self.request(self.user_token, 'no_exists') - self.assertEqual( - response.status_code, - status.HTTP_404_NOT_FOUND) - self.assertEqual( - content_data.get('detail'), - 'Not found.') + response, content_data = self.request(self.user_token, "no_exists") + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) + self.assertEqual(content_data.get("detail"), "Not found.") class UserUpdateTestCase(TestCase): @@ -324,36 +241,24 @@ def setUp(self): self.user, self.user_token = create_user_and_token() def request(self, user, data, token): - authorization_header = { - 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), - } + authorization_header = {"HTTP_AUTHORIZATION": "Token {}".format(token.key)} request = self.factory.patch( - '/v2/account/user-profile/{}/'.format(self.user.nickname), + "/v2/account/user-profile/{}/".format(self.user.nickname), self.factory._encode_data(data, MULTIPART_CONTENT), MULTIPART_CONTENT, - **authorization_header) - response = UserProfileViewSet.as_view( - {'patch': 'update'})( - request, - pk=user.pk, - nickname=user.nickname, - partial=True + **authorization_header + ) + response = UserProfileViewSet.as_view({"patch": "update"})( + request, pk=user.pk, nickname=user.nickname, partial=True ) response.render() content_data = json.loads(response.content) - return (response, content_data,) + return (response, content_data) def test_okay(self): - new_locale = 'Maceió - Alagoas' + new_locale = "Maceió - Alagoas" response, content_data = self.request( - self.user, - { - 'locale': new_locale, - }, - self.user_token) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) - self.assertEqual( - content_data.get('locale'), - new_locale) + self.user, {"locale": new_locale}, self.user_token + ) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(content_data.get("locale"), new_locale) diff --git a/bothub/api/v2/tests/test_evaluate.py b/bothub/api/v2/tests/test_evaluate.py index 771af98e..5e083be8 100644 --- a/bothub/api/v2/tests/test_evaluate.py +++ b/bothub/api/v2/tests/test_evaluate.py @@ -17,356 +17,305 @@ # TestCases + class ListEvaluateTestCase(TestCase): def setUp(self): self.factory = RequestFactory() - self.owner, self.owner_token = create_user_and_token('owner') + self.owner, self.owner_token = create_user_and_token("owner") self.user, self.token = create_user_and_token() self.repository = Repository.objects.create( owner=self.owner, - name='Testing', - slug='test', - language=languages.LANGUAGE_EN + name="Testing", + slug="test", + language=languages.LANGUAGE_EN, ) self.repository_update = RepositoryUpdate.objects.create( repository=self.repository, language=languages.LANGUAGE_EN, - algorithm='statistical_model', + algorithm="statistical_model", ) self.example_1 = RepositoryExample.objects.create( - repository_update=self.repository_update, - text="test", - intent="greet", + repository_update=self.repository_update, text="test", intent="greet" ) self.repository_evaluate = RepositoryEvaluate.objects.create( - repository_update=self.repository_update, - text="test", - intent="greet" + repository_update=self.repository_update, text="test", intent="greet" ) def request(self, token): - authorization_header = { - 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), - } + authorization_header = {"HTTP_AUTHORIZATION": "Token {}".format(token.key)} request = self.factory.get( - '/v2/evaluate/?repository_uuid={}'.format( - self.repository.uuid - ), **authorization_header + "/v2/evaluate/?repository_uuid={}".format(self.repository.uuid), + **authorization_header ) - response = EvaluateViewSet.as_view({'get': 'list'})( - request, - repository_uuid=self.repository.uuid + response = EvaluateViewSet.as_view({"get": "list"})( + request, repository_uuid=self.repository.uuid ) response.render() content_data = json.loads(response.content) - return (response, content_data,) + return (response, content_data) def test_okay(self): response, content_data = self.request(self.owner_token) - self.assertEqual(content_data['count'], 1) - self.assertEqual(len(content_data['results']), 1) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) + self.assertEqual(content_data["count"], 1) + self.assertEqual(len(content_data["results"]), 1) + self.assertEqual(response.status_code, status.HTTP_200_OK) class NewEvaluateTestCase(TestCase): def setUp(self): self.factory = RequestFactory() - self.owner, self.owner_token = create_user_and_token('owner') + self.owner, self.owner_token = create_user_and_token("owner") self.user, self.token = create_user_and_token() self.repository = Repository.objects.create( owner=self.owner, - name='Testing', - slug='test', - language=languages.LANGUAGE_EN + name="Testing", + slug="test", + language=languages.LANGUAGE_EN, ) self.repository_update = RepositoryUpdate.objects.create( repository=self.repository, language=languages.LANGUAGE_EN, - algorithm='statistical_model', + algorithm="statistical_model", ) self.example_1 = RepositoryExample.objects.create( - repository_update=self.repository_update, - text="test", - intent="greet", + repository_update=self.repository_update, text="test", intent="greet" ) def request(self, data, token): - authorization_header = { - 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), - } + authorization_header = {"HTTP_AUTHORIZATION": "Token {}".format(token.key)} request = self.factory.post( - '/v2/evaluate/?repository_uuid={}'.format( - self.repository.uuid - ), + "/v2/evaluate/?repository_uuid={}".format(self.repository.uuid), json.dumps(data), - content_type='application/json', + content_type="application/json", **authorization_header ) - response = EvaluateViewSet.as_view({'post': 'create'})(request) + response = EvaluateViewSet.as_view({"post": "create"})(request) response.render() content_data = json.loads(response.content) - return (response, content_data,) + return (response, content_data) def test_okay(self): response, content_data = self.request( { - 'repository': str(self.repository.uuid), - 'text': 'haha', - 'language': languages.LANGUAGE_EN, - 'intent': 'greet', - 'entities': [] - }, self.owner_token + "repository": str(self.repository.uuid), + "text": "haha", + "language": languages.LANGUAGE_EN, + "intent": "greet", + "entities": [], + }, + self.owner_token, ) - self.assertEqual( - response.status_code, - status.HTTP_201_CREATED) + self.assertEqual(response.status_code, status.HTTP_201_CREATED) def test_intent(self): response, content_data = self.request( { - 'repository': str(self.repository.uuid), - 'text': 'haha', - 'language': languages.LANGUAGE_EN, - 'intent': '', - 'entities': [] - }, self.owner_token + "repository": str(self.repository.uuid), + "text": "haha", + "language": languages.LANGUAGE_EN, + "intent": "", + "entities": [], + }, + self.owner_token, ) - self.assertEqual( - response.status_code, - status.HTTP_400_BAD_REQUEST) - self.assertIn('intent', content_data) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + self.assertIn("intent", content_data) def test_entities_not_exists(self): response, content_data = self.request( { - 'repository': str(self.repository.uuid), - 'text': 'haha', - 'language': languages.LANGUAGE_EN, - 'intent': 'greet', - 'entities': [{"entity": "hello", "start": 0, "end": 3}] - }, self.owner_token + "repository": str(self.repository.uuid), + "text": "haha", + "language": languages.LANGUAGE_EN, + "intent": "greet", + "entities": [{"entity": "hello", "start": 0, "end": 3}], + }, + self.owner_token, ) - self.assertEqual( - response.status_code, - status.HTTP_400_BAD_REQUEST) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) - self.assertIn('entities', content_data) + self.assertIn("entities", content_data) def test_private_okay(self): response, content_data = self.request( { - 'repository': str(self.repository.uuid), - 'text': 'haha', - 'language': languages.LANGUAGE_EN, - 'intent': 'greet', - 'entities': [] - }, self.token + "repository": str(self.repository.uuid), + "text": "haha", + "language": languages.LANGUAGE_EN, + "intent": "greet", + "entities": [], + }, + self.token, ) - self.assertEqual( - response.status_code, - status.HTTP_403_FORBIDDEN) + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) class EvaluateDestroyTestCase(TestCase): def setUp(self): self.factory = RequestFactory() - self.owner, self.owner_token = create_user_and_token('owner') + self.owner, self.owner_token = create_user_and_token("owner") self.user, self.token = create_user_and_token() self.repository = Repository.objects.create( owner=self.owner, - name='Testing', - slug='test', - language=languages.LANGUAGE_EN + name="Testing", + slug="test", + language=languages.LANGUAGE_EN, ) self.repository_update = RepositoryUpdate.objects.create( - repository=self.repository, - language='en', - algorithm='statistical_model', + repository=self.repository, language="en", algorithm="statistical_model" ) self.example_1 = RepositoryExample.objects.create( - repository_update=self.repository_update, - text="test", - intent="greet", + repository_update=self.repository_update, text="test", intent="greet" ) self.repository_evaluate = RepositoryEvaluate.objects.create( - repository_update=self.repository_update, - text="test", - intent="greet" + repository_update=self.repository_update, text="test", intent="greet" ) def request(self, token): - authorization_header = { - 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), - } + authorization_header = {"HTTP_AUTHORIZATION": "Token {}".format(token.key)} request = self.factory.delete( - '/v2/evaluate/{}/?repository_uuid={}'.format( - self.repository_evaluate.id, - self.repository.uuid - ), **authorization_header + "/v2/evaluate/{}/?repository_uuid={}".format( + self.repository_evaluate.id, self.repository.uuid + ), + **authorization_header ) - response = EvaluateViewSet.as_view( - {'delete': 'destroy'})( + response = EvaluateViewSet.as_view({"delete": "destroy"})( request, pk=self.repository_evaluate.id, - repository_uuid=self.repository.uuid + repository_uuid=self.repository.uuid, ) return response def test_okay(self): response = self.request(self.owner_token) - self.assertEqual( - response.status_code, - status.HTTP_204_NO_CONTENT) + self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) def test_private_okay(self): response = self.request(self.token) - self.assertEqual( - response.status_code, - status.HTTP_403_FORBIDDEN) + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) def test_already_deleted(self): self.repository_evaluate.delete() response = self.request(self.owner_token) - self.assertEqual( - response.status_code, - status.HTTP_204_NO_CONTENT) - self.assertIsNotNone( - self.repository_evaluate.deleted_in - ) + self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) + self.assertIsNotNone(self.repository_evaluate.deleted_in) class EvaluateUpdateTestCase(TestCase): def setUp(self): self.factory = RequestFactory() - self.owner, self.owner_token = create_user_and_token('owner') + self.owner, self.owner_token = create_user_and_token("owner") self.user, self.token = create_user_and_token() self.repository = Repository.objects.create( owner=self.owner, - name='Testing', - slug='test', - language=languages.LANGUAGE_EN + name="Testing", + slug="test", + language=languages.LANGUAGE_EN, ) self.repository_update = RepositoryUpdate.objects.create( - repository=self.repository, - language='en', - algorithm='statistical_model', + repository=self.repository, language="en", algorithm="statistical_model" ) self.example_1 = RepositoryExample.objects.create( - repository_update=self.repository_update, - text="test", - intent="greet", + repository_update=self.repository_update, text="test", intent="greet" ) self.repository_evaluate = RepositoryEvaluate.objects.create( - repository_update=self.repository_update, - text="test", - intent="greet" + repository_update=self.repository_update, text="test", intent="greet" ) def request(self, data, token): - authorization_header = { - 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), - } + authorization_header = {"HTTP_AUTHORIZATION": "Token {}".format(token.key)} request = self.factory.patch( - '/v2/evaluate/{}/?repository_uuid={}'.format( - self.repository_evaluate.id, - self.repository.uuid + "/v2/evaluate/{}/?repository_uuid={}".format( + self.repository_evaluate.id, self.repository.uuid ), json.dumps(data), - content_type='application/json', + content_type="application/json", **authorization_header ) - response = EvaluateViewSet.as_view( - {'patch': 'update'})( + response = EvaluateViewSet.as_view({"patch": "update"})( request, pk=self.repository_evaluate.id, - repository_uuid=self.repository.uuid + repository_uuid=self.repository.uuid, ) response.render() content_data = json.loads(response.content) - return (response, content_data,) + return (response, content_data) def test_okay(self): - text = 'testing' + text = "testing" response, content_data = self.request( { - 'repository': str(self.repository.uuid), - 'text': text, - 'language': languages.LANGUAGE_EN, - 'intent': 'greet', - 'entities': [] - }, self.owner_token - ) - self.assertEqual(content_data['text'], text) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) + "repository": str(self.repository.uuid), + "text": text, + "language": languages.LANGUAGE_EN, + "intent": "greet", + "entities": [], + }, + self.owner_token, + ) + self.assertEqual(content_data["text"], text) + self.assertEqual(response.status_code, status.HTTP_200_OK) def test_private_okay(self): response, content_data = self.request( { - 'repository': str(self.repository.uuid), - 'text': 'testing', - 'language': languages.LANGUAGE_EN, - 'intent': 'greet', - 'entities': [] - }, self.token) - self.assertEqual( - response.status_code, - status.HTTP_403_FORBIDDEN) + "repository": str(self.repository.uuid), + "text": "testing", + "language": languages.LANGUAGE_EN, + "intent": "greet", + "entities": [], + }, + self.token, + ) + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) class ListEvaluateResultTestCase(TestCase): def setUp(self): self.factory = RequestFactory() - self.owner, self.owner_token = create_user_and_token('owner') + self.owner, self.owner_token = create_user_and_token("owner") self.user, self.token = create_user_and_token() self.repository = Repository.objects.create( owner=self.owner, - name='Testing', - slug='test', - language=languages.LANGUAGE_EN + name="Testing", + slug="test", + language=languages.LANGUAGE_EN, ) for x in range(0, 2): intent_results = RepositoryEvaluateResultScore.objects.create( - f1_score=0.976, - precision=0.978, - accuracy=0.976, + f1_score=0.976, precision=0.978, accuracy=0.976 ) entity_results = RepositoryEvaluateResultScore.objects.create( - f1_score=0.977, - precision=0.978, - accuracy=0.978, + f1_score=0.977, precision=0.978, accuracy=0.978 ) evaluate_log = [ @@ -375,177 +324,139 @@ def setUp(self): "intent": "greet", "intent_prediction": { "name": "greet", - "confidence": 0.9263743763408538 + "confidence": 0.9263743763408538, }, - "status": "success" + "status": "success", }, { "text": "howdy", "intent": "greet", "intent_prediction": { "name": "greet", - "confidence": 0.8099720606047796 + "confidence": 0.8099720606047796, }, - "status": "success" + "status": "success", }, { "text": "hey there", "intent": "greet", "intent_prediction": { "name": "greet", - "confidence": 0.8227075176309955 + "confidence": 0.8227075176309955, }, - "status": "success" + "status": "success", }, { "text": "test with nlu", "intent": "restaurant_search", "intent_prediction": { "name": "goodbye", - "confidence": 0.3875259420712092 + "confidence": 0.3875259420712092, }, - "status": "error" - } + "status": "error", + }, ] - sample_url = 'https://s3.amazonaws.com/bothub-sample' + sample_url = "https://s3.amazonaws.com/bothub-sample" evaluate_result = RepositoryEvaluateResult.objects.create( repository_update=self.repository.current_update(), intent_results=intent_results, entity_results=entity_results, - matrix_chart='{}/confmat.png'.format(sample_url), - confidence_chart='{}/hist.png'.format(sample_url), + matrix_chart="{}/confmat.png".format(sample_url), + confidence_chart="{}/hist.png".format(sample_url), log=json.dumps(evaluate_log), ) intent_score_1 = RepositoryEvaluateResultScore.objects.create( - precision=1.0, - recall=1.0, - f1_score=1.0, - support=11, + precision=1.0, recall=1.0, f1_score=1.0, support=11 ) intent_score_2 = RepositoryEvaluateResultScore.objects.create( - precision=0.89, - recall=1.0, - f1_score=0.94, - support=8, + precision=0.89, recall=1.0, f1_score=0.94, support=8 ) intent_score_3 = RepositoryEvaluateResultScore.objects.create( - precision=1.0, - recall=1.0, - f1_score=1.0, - support=8, + precision=1.0, recall=1.0, f1_score=1.0, support=8 ) intent_score_4 = RepositoryEvaluateResultScore.objects.create( - precision=1.0, - recall=0.93, - f1_score=0.97, - support=15, + precision=1.0, recall=0.93, f1_score=0.97, support=15 ) RepositoryEvaluateResultIntent.objects.create( - evaluate_result=evaluate_result, - intent='affirm', - score=intent_score_1, + evaluate_result=evaluate_result, intent="affirm", score=intent_score_1 ) RepositoryEvaluateResultIntent.objects.create( - evaluate_result=evaluate_result, - intent='goodbye', - score=intent_score_2, + evaluate_result=evaluate_result, intent="goodbye", score=intent_score_2 ) RepositoryEvaluateResultIntent.objects.create( - evaluate_result=evaluate_result, - intent='greet', - score=intent_score_3, + evaluate_result=evaluate_result, intent="greet", score=intent_score_3 ) RepositoryEvaluateResultIntent.objects.create( evaluate_result=evaluate_result, - intent='restaurant_search', + intent="restaurant_search", score=intent_score_4, ) entity_score_1 = RepositoryEvaluateResultScore.objects.create( - precision=1.0, - recall=0.90, - f1_score=0.95, - support=10, + precision=1.0, recall=0.90, f1_score=0.95, support=10 ) entity_score_2 = RepositoryEvaluateResultScore.objects.create( - precision=1.0, - recall=0.75, - f1_score=0.86, - support=8, + precision=1.0, recall=0.75, f1_score=0.86, support=8 ) RepositoryEvaluateResultEntity.objects.create( - evaluate_result=evaluate_result, - entity='cuisine', - score=entity_score_1, + evaluate_result=evaluate_result, entity="cuisine", score=entity_score_1 ) RepositoryEvaluateResultEntity.objects.create( - evaluate_result=evaluate_result, - entity='greet', - score=entity_score_2, + evaluate_result=evaluate_result, entity="greet", score=entity_score_2 ) def request(self, token): - authorization_header = { - 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), - } + authorization_header = {"HTTP_AUTHORIZATION": "Token {}".format(token.key)} request = self.factory.get( - '/v2/evaluate/results/?repository_uuid={}'.format( - self.repository.uuid - ), **authorization_header + "/v2/evaluate/results/?repository_uuid={}".format(self.repository.uuid), + **authorization_header ) - response = ResultsListViewSet.as_view({'get': 'list'})( - request, - repository_uuid=self.repository.uuid + response = ResultsListViewSet.as_view({"get": "list"})( + request, repository_uuid=self.repository.uuid ) response.render() content_data = json.loads(response.content) - return (response, content_data,) + return (response, content_data) def test_okay(self): response, content_data = self.request(self.owner_token) - self.assertEqual(content_data['count'], 2) - self.assertEqual(len(content_data['results']), 2) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) + self.assertEqual(content_data["count"], 2) + self.assertEqual(len(content_data["results"]), 2) + self.assertEqual(response.status_code, status.HTTP_200_OK) class ListEvaluateResultTestFilterCase(TestCase): def setUp(self): self.factory = RequestFactory() - self.owner, self.owner_token = create_user_and_token('owner') + self.owner, self.owner_token = create_user_and_token("owner") self.user, self.token = create_user_and_token() self.repository = Repository.objects.create( owner=self.owner, - name='Testing', - slug='test', - language=languages.LANGUAGE_EN + name="Testing", + slug="test", + language=languages.LANGUAGE_EN, ) intent_results = RepositoryEvaluateResultScore.objects.create( - f1_score=0.976, - precision=0.978, - accuracy=0.976, + f1_score=0.976, precision=0.978, accuracy=0.976 ) entity_results = RepositoryEvaluateResultScore.objects.create( - f1_score=0.977, - precision=0.978, - accuracy=0.978, + f1_score=0.977, precision=0.978, accuracy=0.978 ) evaluate_log = [ @@ -554,202 +465,151 @@ def setUp(self): "intent": "greet", "intent_prediction": { "name": "greet", - "confidence": 0.9263743763408538 + "confidence": 0.9263743763408538, }, - "status": "success" + "status": "success", }, { "text": "howdy", "intent": "greet", "intent_prediction": { "name": "greet", - "confidence": 0.8099720606047796 + "confidence": 0.8099720606047796, }, - "status": "success" + "status": "success", }, { "text": "hey there", "intent": "greet", "intent_prediction": { "name": "greet", - "confidence": 0.8227075176309955 + "confidence": 0.8227075176309955, }, - "status": "success" + "status": "success", }, { "text": "test with nlu", "intent": "restaurant_search", "intent_prediction": { "name": "goodbye", - "confidence": 0.3875259420712092 + "confidence": 0.3875259420712092, }, - "status": "error" - } + "status": "error", + }, ] - sample_url = 'https://s3.amazonaws.com/bothub-sample' + sample_url = "https://s3.amazonaws.com/bothub-sample" self.evaluate_result = RepositoryEvaluateResult.objects.create( repository_update=self.repository.current_update(), intent_results=intent_results, entity_results=entity_results, - matrix_chart='{}/confmat.png'.format(sample_url), - confidence_chart='{}/hist.png'.format(sample_url), + matrix_chart="{}/confmat.png".format(sample_url), + confidence_chart="{}/hist.png".format(sample_url), log=json.dumps(evaluate_log), ) intent_score_1 = RepositoryEvaluateResultScore.objects.create( - precision=1.0, - recall=1.0, - f1_score=1.0, - support=11, + precision=1.0, recall=1.0, f1_score=1.0, support=11 ) intent_score_2 = RepositoryEvaluateResultScore.objects.create( - precision=0.89, - recall=1.0, - f1_score=0.94, - support=8, + precision=0.89, recall=1.0, f1_score=0.94, support=8 ) intent_score_3 = RepositoryEvaluateResultScore.objects.create( - precision=1.0, - recall=1.0, - f1_score=1.0, - support=8, + precision=1.0, recall=1.0, f1_score=1.0, support=8 ) intent_score_4 = RepositoryEvaluateResultScore.objects.create( - precision=1.0, - recall=0.93, - f1_score=0.97, - support=15, + precision=1.0, recall=0.93, f1_score=0.97, support=15 ) RepositoryEvaluateResultIntent.objects.create( - evaluate_result=self.evaluate_result, - intent='affirm', - score=intent_score_1, + evaluate_result=self.evaluate_result, intent="affirm", score=intent_score_1 ) RepositoryEvaluateResultIntent.objects.create( - evaluate_result=self.evaluate_result, - intent='goodbye', - score=intent_score_2, + evaluate_result=self.evaluate_result, intent="goodbye", score=intent_score_2 ) RepositoryEvaluateResultIntent.objects.create( - evaluate_result=self.evaluate_result, - intent='greet', - score=intent_score_3, + evaluate_result=self.evaluate_result, intent="greet", score=intent_score_3 ) RepositoryEvaluateResultIntent.objects.create( evaluate_result=self.evaluate_result, - intent='restaurant_search', + intent="restaurant_search", score=intent_score_4, ) entity_score_1 = RepositoryEvaluateResultScore.objects.create( - precision=1.0, - recall=0.90, - f1_score=0.95, - support=10, + precision=1.0, recall=0.90, f1_score=0.95, support=10 ) entity_score_2 = RepositoryEvaluateResultScore.objects.create( - precision=1.0, - recall=0.75, - f1_score=0.86, - support=8, + precision=1.0, recall=0.75, f1_score=0.86, support=8 ) RepositoryEvaluateResultEntity.objects.create( - evaluate_result=self.evaluate_result, - entity='cuisine', - score=entity_score_1, + evaluate_result=self.evaluate_result, entity="cuisine", score=entity_score_1 ) RepositoryEvaluateResultEntity.objects.create( - evaluate_result=self.evaluate_result, - entity='greet', - score=entity_score_2, + evaluate_result=self.evaluate_result, entity="greet", score=entity_score_2 ) def request(self, token, params): - authorization_header = { - 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), - } + authorization_header = {"HTTP_AUTHORIZATION": "Token {}".format(token.key)} request = self.factory.get( - '/v2/evaluate/results/{}/{}'.format( - self.evaluate_result.id, - params - ), **authorization_header + "/v2/evaluate/results/{}/{}".format(self.evaluate_result.id, params), + **authorization_header ) - response = ResultsListViewSet.as_view({'get': 'retrieve'})( - request, - pk=self.evaluate_result.id, - repository_uuid=self.repository.uuid + response = ResultsListViewSet.as_view({"get": "retrieve"})( + request, pk=self.evaluate_result.id, repository_uuid=self.repository.uuid ) response.render() content_data = json.loads(response.content) - return (response, content_data,) + return (response, content_data) def test_okay(self): response, content_data = self.request( - self.owner_token, - '?repository_uuid={}'.format( - self.repository.uuid - ) + self.owner_token, "?repository_uuid={}".format(self.repository.uuid) ) - self.assertEqual(len(content_data['log']), 4) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) + self.assertEqual(len(content_data["log"]), 4) + self.assertEqual(response.status_code, status.HTTP_200_OK) def test_okay_intent_filter(self): response, content_data = self.request( self.owner_token, - '?repository_uuid={}&intent=greet&min=0&max=100'.format( + "?repository_uuid={}&intent=greet&min=0&max=100".format( self.repository.uuid - ) + ), ) - self.assertEqual(len(content_data['log']), 3) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) + self.assertEqual(len(content_data["log"]), 3) + self.assertEqual(response.status_code, status.HTTP_200_OK) def test_okay_without_intent_filter(self): response, content_data = self.request( self.owner_token, - '?repository_uuid={}&min=0&max=100'.format( - self.repository.uuid - ) + "?repository_uuid={}&min=0&max=100".format(self.repository.uuid), ) - self.assertEqual(len(content_data['log']), 4) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) + self.assertEqual(len(content_data["log"]), 4) + self.assertEqual(response.status_code, status.HTTP_200_OK) def test_okay_range_without_intent_filter(self): response, content_data = self.request( self.owner_token, - '?repository_uuid={}&min=50&max=80'.format( - self.repository.uuid - ) + "?repository_uuid={}&min=50&max=80".format(self.repository.uuid), ) - self.assertEqual(len(content_data['log']), 1) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) + self.assertEqual(len(content_data["log"]), 1) + self.assertEqual(response.status_code, status.HTTP_200_OK) def test_okay_range_with_intent_filter(self): response, content_data = self.request( self.owner_token, - '?repository_uuid={}&intent=greet&min=50&max=80'.format( + "?repository_uuid={}&intent=greet&min=50&max=80".format( self.repository.uuid - ) + ), ) - self.assertEqual(len(content_data['log']), 1) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) + self.assertEqual(len(content_data["log"]), 1) + self.assertEqual(response.status_code, status.HTTP_200_OK) diff --git a/bothub/api/v2/tests/test_examples.py b/bothub/api/v2/tests/test_examples.py index c7777a50..56755c87 100644 --- a/bothub/api/v2/tests/test_examples.py +++ b/bothub/api/v2/tests/test_examples.py @@ -17,270 +17,196 @@ class ListExamplesAPITestCase(TestCase): def setUp(self): self.factory = RequestFactory() - self.owner, self.owner_token = create_user_and_token('owner') - self.user, self.user_token = create_user_and_token('user') + self.owner, self.owner_token = create_user_and_token("owner") + self.user, self.user_token = create_user_and_token("user") self.repository = Repository.objects.create( owner=self.owner, - name='Repository 1', - slug='repo', - language=languages.LANGUAGE_EN) + name="Repository 1", + slug="repo", + language=languages.LANGUAGE_EN, + ) self.example_1 = RepositoryExample.objects.create( repository_update=self.repository.current_update(), - text='hi', - intent='greet') + text="hi", + intent="greet", + ) entity_1 = RepositoryExampleEntity.objects.create( - repository_example=self.example_1, - start=0, - end=0, - entity='hi') - entity_1.entity.set_label('greet') + repository_example=self.example_1, start=0, end=0, entity="hi" + ) + entity_1.entity.set_label("greet") entity_1.entity.save() self.example_2 = RepositoryExample.objects.create( repository_update=self.repository.current_update(), - text='hello', - intent='greet') + text="hello", + intent="greet", + ) self.example_3 = RepositoryExample.objects.create( repository_update=self.repository.current_update(), - text='bye', - intent='farewell') + text="bye", + intent="farewell", + ) self.example_4 = RepositoryExample.objects.create( repository_update=self.repository.current_update(), - text='bye bye', - intent='farewell') + text="bye bye", + intent="farewell", + ) self.repository_2 = Repository.objects.create( owner=self.owner, - name='Repository 2', - slug='repo2', - language=languages.LANGUAGE_EN) + name="Repository 2", + slug="repo2", + language=languages.LANGUAGE_EN, + ) self.example_5 = RepositoryExample.objects.create( repository_update=self.repository_2.current_update(), - text='hi', - intent='greet') + text="hi", + intent="greet", + ) self.example_6 = RepositoryExample.objects.create( - repository_update=self.repository_2.current_update( - languages.LANGUAGE_PT), - text='oi', - intent='greet') + repository_update=self.repository_2.current_update(languages.LANGUAGE_PT), + text="oi", + intent="greet", + ) self.translation_6 = RepositoryTranslatedExample.objects.create( - original_example=self.example_6, - language=languages.LANGUAGE_EN, - text='hi') + original_example=self.example_6, language=languages.LANGUAGE_EN, text="hi" + ) def request(self, data={}, token=None): - authorization_header = { - 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), - } if token else {} + authorization_header = ( + {"HTTP_AUTHORIZATION": "Token {}".format(token.key)} if token else {} + ) - request = self.factory.get( - '/v2/examples/', - data, - **authorization_header) + request = self.factory.get("/v2/examples/", data, **authorization_header) - response = ExamplesViewSet.as_view({'get': 'list'})(request) + response = ExamplesViewSet.as_view({"get": "list"})(request) response.render() content_data = json.loads(response.content) - return (response, content_data,) + return (response, content_data) def test_okay(self): - response, content_data = self.request({ - 'repository_uuid': self.repository.uuid, - }) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) - self.assertEqual( - content_data.get('count'), - 4) + response, content_data = self.request({"repository_uuid": self.repository.uuid}) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(content_data.get("count"), 4) - response, content_data = self.request({ - 'repository_uuid': self.repository_2.uuid, - }) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) - self.assertEqual( - content_data.get('count'), - 2) + response, content_data = self.request( + {"repository_uuid": self.repository_2.uuid} + ) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(content_data.get("count"), 2) def test_deleted(self): self.example_1.delete() - response, content_data = self.request({ - 'repository_uuid': self.repository.uuid, - }) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) - self.assertEqual( - content_data.get('count'), - 3) + response, content_data = self.request({"repository_uuid": self.repository.uuid}) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(content_data.get("count"), 3) def test_withuout_repository_uuid(self): response, content_data = self.request() - self.assertEqual( - response.status_code, - status.HTTP_400_BAD_REQUEST) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) def test_filter_text(self): - response, content_data = self.request({ - 'repository_uuid': self.repository.uuid, - 'text': self.example_1.text, - }) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) - self.assertEqual( - content_data.get('count'), - 1) - self.assertEqual( - content_data.get('results')[0].get('id'), - self.example_1.id) + response, content_data = self.request( + {"repository_uuid": self.repository.uuid, "text": self.example_1.text} + ) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(content_data.get("count"), 1) + self.assertEqual(content_data.get("results")[0].get("id"), self.example_1.id) def test_filter_part_text(self): - response, content_data = self.request({ - 'repository_uuid': self.repository.uuid, - 'search': 'h', - }) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) - self.assertEqual( - content_data.get('count'), - 2) + response, content_data = self.request( + {"repository_uuid": self.repository.uuid, "search": "h"} + ) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(content_data.get("count"), 2) def test_filter_language(self): - response, content_data = self.request({ - 'repository_uuid': self.repository_2.uuid, - 'language': languages.LANGUAGE_PT - }) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) - self.assertEqual( - content_data.get('count'), - 1) + response, content_data = self.request( + { + "repository_uuid": self.repository_2.uuid, + "language": languages.LANGUAGE_PT, + } + ) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(content_data.get("count"), 1) def test_filter_has_translation(self): - response, content_data = self.request({ - 'repository_uuid': self.repository_2.uuid, - 'has_translation': False - }) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) - self.assertEqual( - content_data.get('count'), - 1) + response, content_data = self.request( + {"repository_uuid": self.repository_2.uuid, "has_translation": False} + ) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(content_data.get("count"), 1) - response, content_data = self.request({ - 'repository_uuid': self.repository_2.uuid, - 'has_translation': True - }) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) - self.assertEqual( - content_data.get('count'), - 1) + response, content_data = self.request( + {"repository_uuid": self.repository_2.uuid, "has_translation": True} + ) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(content_data.get("count"), 1) def test_filter_has_not_translation_to(self): - response, content_data = self.request({ - 'repository_uuid': self.repository_2.uuid, - 'has_not_translation_to': languages.LANGUAGE_ES, - }) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) - self.assertEqual( - content_data.get('count'), - 2) + response, content_data = self.request( + { + "repository_uuid": self.repository_2.uuid, + "has_not_translation_to": languages.LANGUAGE_ES, + } + ) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(content_data.get("count"), 2) - response, content_data = self.request({ - 'repository_uuid': self.repository_2.uuid, - 'has_not_translation_to': languages.LANGUAGE_EN, - }) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) - self.assertEqual( - content_data.get('count'), - 1) + response, content_data = self.request( + { + "repository_uuid": self.repository_2.uuid, + "has_not_translation_to": languages.LANGUAGE_EN, + } + ) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(content_data.get("count"), 1) def test_filter_order_by_translation(self): response, content_data = self.request( { - 'repository_uuid': self.repository_2.uuid, - 'order_by_translation': languages.LANGUAGE_EN, + "repository_uuid": self.repository_2.uuid, + "order_by_translation": languages.LANGUAGE_EN, }, - self.owner_token) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) - results = content_data.get('results') - self.assertEqual( - 0, - len(results[0].get('translations'))) - self.assertEqual( - 1, - len(results[1].get('translations'))) + self.owner_token, + ) + self.assertEqual(response.status_code, status.HTTP_200_OK) + results = content_data.get("results") + self.assertEqual(0, len(results[0].get("translations"))) + self.assertEqual(1, len(results[1].get("translations"))) def test_filter_order_by_translation_inverted(self): response, content_data = self.request( { - 'repository_uuid': self.repository_2.uuid, - 'order_by_translation': '-{}'.format(languages.LANGUAGE_EN), + "repository_uuid": self.repository_2.uuid, + "order_by_translation": "-{}".format(languages.LANGUAGE_EN), }, - self.owner_token) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) - results = content_data.get('results') - self.assertEqual( - 1, - len(results[0].get('translations'))) - self.assertEqual( - 0, - len(results[1].get('translations'))) + self.owner_token, + ) + self.assertEqual(response.status_code, status.HTTP_200_OK) + results = content_data.get("results") + self.assertEqual(1, len(results[0].get("translations"))) + self.assertEqual(0, len(results[1].get("translations"))) def test_filter_intent(self): response, content_data = self.request( - { - 'repository_uuid': self.repository.uuid, - 'intent': 'farewell', - }, - self.owner_token) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) - self.assertEqual( - content_data.get('count'), - 2) + {"repository_uuid": self.repository.uuid, "intent": "farewell"}, + self.owner_token, + ) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(content_data.get("count"), 2) def test_filter_label(self): response, content_data = self.request( - { - 'repository_uuid': self.repository.uuid, - 'label': 'greet', - }, - self.owner_token) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) - self.assertEqual( - content_data.get('count'), - 1) + {"repository_uuid": self.repository.uuid, "label": "greet"}, + self.owner_token, + ) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(content_data.get("count"), 1) def test_filter_entity(self): response, content_data = self.request( - { - 'repository_uuid': self.repository.uuid, - 'entity': 'hi', - }, - self.owner_token) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) - self.assertEqual( - content_data.get('count'), - 1) + {"repository_uuid": self.repository.uuid, "entity": "hi"}, self.owner_token + ) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(content_data.get("count"), 1) diff --git a/bothub/api/v2/tests/test_nlp.py b/bothub/api/v2/tests/test_nlp.py index e31ec272..c08cea3e 100644 --- a/bothub/api/v2/tests/test_nlp.py +++ b/bothub/api/v2/tests/test_nlp.py @@ -20,342 +20,268 @@ class TrainStartTrainingTestCase(TestCase): def setUp(self): self.factory = RequestFactory() - self.owner, self.owner_token = create_user_and_token('owner') + self.owner, self.owner_token = create_user_and_token("owner") self.user, self.user_token = create_user_and_token() self.repository = Repository.objects.create( owner=self.owner, - name='Testing', - slug='test', - language=languages.LANGUAGE_EN) + name="Testing", + slug="test", + language=languages.LANGUAGE_EN, + ) self.repository_authorization = RepositoryAuthorization.objects.create( - user=self.user, - repository=self.repository, - role=3, + user=self.user, repository=self.repository, role=3 ) self.repository_update = RepositoryUpdate.objects.create( repository=self.repository, language=languages.LANGUAGE_EN, - algorithm='statistical_model', + algorithm="statistical_model", ) def request(self, token): - authorization_header = { - 'HTTP_AUTHORIZATION': 'Bearer {}'.format(token), - } + authorization_header = {"HTTP_AUTHORIZATION": "Bearer {}".format(token)} request = self.factory.post( - '/v2/repository/nlp/authorization/train/start_training/', + "/v2/repository/nlp/authorization/train/start_training/", json.dumps( - { - 'update_id': self.repository_update.pk, - 'by_user': self.user.pk - } + {"update_id": self.repository_update.pk, "by_user": self.user.pk} ), - content_type='application/json', + content_type="application/json", **authorization_header ) response = RepositoryAuthorizationTrainViewSet.as_view( - {'post': 'start_training'} + {"post": "start_training"} )(request) response.render() content_data = json.loads(response.content) - return (response, content_data,) + return (response, content_data) def test_ok(self): - response, content_data = self.request( - str(self.repository_authorization.uuid) - ) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) + response, content_data = self.request(str(self.repository_authorization.uuid)) + self.assertEqual(response.status_code, status.HTTP_200_OK) def test_not_auth(self): - response, content_data = self.request('NO-TOKEN') - self.assertEqual( - response.status_code, - status.HTTP_401_UNAUTHORIZED) + response, content_data = self.request("NO-TOKEN") + self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED) class TrainGetTextTestCase(TestCase): def setUp(self): self.factory = RequestFactory() - self.owner, self.owner_token = create_user_and_token('owner') + self.owner, self.owner_token = create_user_and_token("owner") self.user, self.user_token = create_user_and_token() self.repository = Repository.objects.create( owner=self.owner, - name='Testing', - slug='test', - language=languages.LANGUAGE_EN) + name="Testing", + slug="test", + language=languages.LANGUAGE_EN, + ) self.repository_authorization = RepositoryAuthorization.objects.create( - user=self.user, - repository=self.repository, - role=3, + user=self.user, repository=self.repository, role=3 ) self.repository_update = RepositoryUpdate.objects.create( repository=self.repository, language=languages.LANGUAGE_EN, - algorithm='statistical_model', + algorithm="statistical_model", ) self.repository_examples = RepositoryExample.objects.create( - repository_update=self.repository_update, - text='hello', - intent='greet' + repository_update=self.repository_update, text="hello", intent="greet" ) def request(self, token): - authorization_header = { - 'HTTP_AUTHORIZATION': 'Bearer {}'.format(token), - } + authorization_header = {"HTTP_AUTHORIZATION": "Bearer {}".format(token)} request = self.factory.get( - '/v2/repository/nlp/authorization/train/get_text/' - '?update_id={}&example_id={}&language={}'.format( + "/v2/repository/nlp/authorization/train/get_text/" + "?update_id={}&example_id={}&language={}".format( self.repository_update.pk, self.repository_examples.pk, - languages.LANGUAGE_EN + languages.LANGUAGE_EN, ), **authorization_header ) - response = RepositoryAuthorizationTrainViewSet.as_view( - {'get': 'get_text'} - )(request) + response = RepositoryAuthorizationTrainViewSet.as_view({"get": "get_text"})( + request + ) response.render() content_data = json.loads(response.content) - return (response, content_data,) + return (response, content_data) def test_ok(self): - response, content_data = self.request( - str(self.repository_authorization.uuid) - ) - self.assertEqual( - content_data.get('get_text'), - 'hello' - ) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) + response, content_data = self.request(str(self.repository_authorization.uuid)) + self.assertEqual(content_data.get("get_text"), "hello") + self.assertEqual(response.status_code, status.HTTP_200_OK) def test_not_auth(self): - response, content_data = self.request('NO-TOKEN') - self.assertEqual( - response.status_code, - status.HTTP_401_UNAUTHORIZED) + response, content_data = self.request("NO-TOKEN") + self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED) class TrainGetEntitiesTestCase(TestCase): def setUp(self): self.factory = RequestFactory() - self.owner, self.owner_token = create_user_and_token('owner') + self.owner, self.owner_token = create_user_and_token("owner") self.user, self.user_token = create_user_and_token() self.repository = Repository.objects.create( owner=self.owner, - name='Testing', - slug='test', - language=languages.LANGUAGE_EN) + name="Testing", + slug="test", + language=languages.LANGUAGE_EN, + ) self.repository_authorization = RepositoryAuthorization.objects.create( - user=self.user, - repository=self.repository, - role=3, + user=self.user, repository=self.repository, role=3 ) self.repository_update = RepositoryUpdate.objects.create( repository=self.repository, language=languages.LANGUAGE_EN, - algorithm='statistical_model', + algorithm="statistical_model", ) self.repository_examples = RepositoryExample.objects.create( - repository_update=self.repository_update, - text='hello', - intent='greet' + repository_update=self.repository_update, text="hello", intent="greet" ) RepositoryExampleEntity.objects.create( - repository_example=self.repository_examples, - start=11, - end=18, - entity='name' + repository_example=self.repository_examples, start=11, end=18, entity="name" ) def request(self, token): - authorization_header = { - 'HTTP_AUTHORIZATION': 'Bearer {}'.format(token), - } + authorization_header = {"HTTP_AUTHORIZATION": "Bearer {}".format(token)} request = self.factory.get( - '/v2/repository/nlp/authorization/train/get_entities/' - '?update_id={}&example_id={}&language={}'.format( + "/v2/repository/nlp/authorization/train/get_entities/" + "?update_id={}&example_id={}&language={}".format( self.repository_update.pk, self.repository_examples.pk, - languages.LANGUAGE_EN + languages.LANGUAGE_EN, ), **authorization_header ) - response = RepositoryAuthorizationTrainViewSet.as_view( - {'get': 'get_entities'} - )(request) + response = RepositoryAuthorizationTrainViewSet.as_view({"get": "get_entities"})( + request + ) response.render() content_data = json.loads(response.content) - return (response, content_data,) + return (response, content_data) def test_ok(self): - response, content_data = self.request( - str(self.repository_authorization.uuid) - ) - self.assertEqual( - len(content_data.get('entities')), - 1 - ) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) + response, content_data = self.request(str(self.repository_authorization.uuid)) + self.assertEqual(len(content_data.get("entities")), 1) + self.assertEqual(response.status_code, status.HTTP_200_OK) def test_not_auth(self): - response, content_data = self.request('NO-TOKEN') - self.assertEqual( - response.status_code, - status.HTTP_401_UNAUTHORIZED) + response, content_data = self.request("NO-TOKEN") + self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED) class TrainFailTestCase(TestCase): def setUp(self): self.factory = RequestFactory() - self.owner, self.owner_token = create_user_and_token('owner') + self.owner, self.owner_token = create_user_and_token("owner") self.user, self.user_token = create_user_and_token() self.repository = Repository.objects.create( owner=self.owner, - name='Testing', - slug='test', - language=languages.LANGUAGE_EN) + name="Testing", + slug="test", + language=languages.LANGUAGE_EN, + ) self.repository_authorization = RepositoryAuthorization.objects.create( - user=self.user, - repository=self.repository, - role=3, + user=self.user, repository=self.repository, role=3 ) self.repository_update = RepositoryUpdate.objects.create( repository=self.repository, language=languages.LANGUAGE_EN, - algorithm='statistical_model', + algorithm="statistical_model", ) def request(self, token): - authorization_header = { - 'HTTP_AUTHORIZATION': 'Bearer {}'.format(token), - } + authorization_header = {"HTTP_AUTHORIZATION": "Bearer {}".format(token)} request = self.factory.post( - '/v2/repository/nlp/authorization/train/train_fail/', - json.dumps( - { - 'update_id': self.repository_update.pk - } - ), - content_type='application/json', + "/v2/repository/nlp/authorization/train/train_fail/", + json.dumps({"update_id": self.repository_update.pk}), + content_type="application/json", **authorization_header ) - response = RepositoryAuthorizationTrainViewSet.as_view( - {'post': 'train_fail'} - )(request) + response = RepositoryAuthorizationTrainViewSet.as_view({"post": "train_fail"})( + request + ) response.render() content_data = json.loads(response.content) - return (response, content_data,) + return (response, content_data) def test_ok(self): - response, content_data = self.request( - str(self.repository_authorization.uuid) - ) + response, content_data = self.request(str(self.repository_authorization.uuid)) self.assertIsNotNone( - RepositoryUpdate.objects.get( - pk=self.repository_update.pk - ).failed_at + RepositoryUpdate.objects.get(pk=self.repository_update.pk).failed_at ) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) + self.assertEqual(response.status_code, status.HTTP_200_OK) def test_not_auth(self): - response, content_data = self.request('NO-TOKEN') - self.assertEqual( - response.status_code, - status.HTTP_401_UNAUTHORIZED) + response, content_data = self.request("NO-TOKEN") + self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED) class AuthorizationInfoTestCase(TestCase): def setUp(self): self.factory = RequestFactory() - self.owner, self.owner_token = create_user_and_token('owner') + self.owner, self.owner_token = create_user_and_token("owner") self.user, self.user_token = create_user_and_token() self.repository = Repository.objects.create( owner=self.owner, - name='Testing', - slug='test', - language=languages.LANGUAGE_EN) + name="Testing", + slug="test", + language=languages.LANGUAGE_EN, + ) self.repository_authorization = RepositoryAuthorization.objects.create( - user=self.user, - repository=self.repository, - role=3, + user=self.user, repository=self.repository, role=3 ) self.repository_update = RepositoryUpdate.objects.create( repository=self.repository, language=languages.LANGUAGE_EN, - algorithm='statistical_model', + algorithm="statistical_model", ) self.repository_examples = RepositoryExample.objects.create( - repository_update=self.repository_update, - text='hello', - intent='greet' + repository_update=self.repository_update, text="hello", intent="greet" ) self.repository_entity = RepositoryExampleEntity.objects.create( - repository_example=self.repository_examples, - start=11, - end=18, - entity='name' + repository_example=self.repository_examples, start=11, end=18, entity="name" ) def request(self, token): - authorization_header = { - 'HTTP_AUTHORIZATION': 'Bearer {}'.format(token), - } + authorization_header = {"HTTP_AUTHORIZATION": "Bearer {}".format(token)} request = self.factory.get( - '/v2/repository/nlp/authorization/info/{}/'.format( - token - ), + "/v2/repository/nlp/authorization/info/{}/".format(token), **authorization_header ) - response = RepositoryAuthorizationInfoViewSet.as_view( - {'get': 'retrieve'} - )(request, pk=token) + response = RepositoryAuthorizationInfoViewSet.as_view({"get": "retrieve"})( + request, pk=token + ) response.render() content_data = json.loads(response.content) - return (response, content_data,) + return (response, content_data) def test_ok(self): - response, content_data = self.request( - str(self.repository_authorization.uuid) - ) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) + response, content_data = self.request(str(self.repository_authorization.uuid)) + self.assertEqual(response.status_code, status.HTTP_200_OK) def test_not_auth(self): - response, content_data = self.request('NO-TOKEN') - self.assertEqual( - response.status_code, - status.HTTP_401_UNAUTHORIZED) + response, content_data = self.request("NO-TOKEN") + self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED) diff --git a/bothub/api/v2/tests/test_repository.py b/bothub/api/v2/tests/test_repository.py index c7b57601..36d3d2ee 100644 --- a/bothub/api/v2/tests/test_repository.py +++ b/bothub/api/v2/tests/test_repository.py @@ -27,8 +27,7 @@ from bothub.api.v2.repository.views import RepositoryCategoriesView from bothub.api.v2.repository.views import SearchRepositoriesViewSet from bothub.api.v2.repository.views import RepositoryAuthorizationViewSet -from bothub.api.v2.repository.views import \ - RepositoryAuthorizationRequestsViewSet +from bothub.api.v2.repository.views import RepositoryAuthorizationRequestsViewSet from bothub.api.v2.repository.views import RepositoryExampleViewSet from bothub.api.v2.repository.views import RepositoryUpdatesViewSet from bothub.api.v2.repository.serializers import RepositorySerializer @@ -37,24 +36,18 @@ def get_valid_mockups(categories): return [ { - 'name': 'Repository 1', - 'slug': 'repository-1', - 'language': languages.LANGUAGE_EN, - 'categories': [ - category.pk - for category in categories - ], - 'is_private': True, + "name": "Repository 1", + "slug": "repository-1", + "language": languages.LANGUAGE_EN, + "categories": [category.pk for category in categories], + "is_private": True, }, { - 'name': 'Repository 2', - 'slug': 'repo2', - 'language': languages.LANGUAGE_PT, - 'categories': [ - category.pk - for category in categories - ], - 'is_private': False, + "name": "Repository 2", + "slug": "repo2", + "language": languages.LANGUAGE_PT, + "categories": [category.pk for category in categories], + "is_private": False, }, ] @@ -62,52 +55,38 @@ def get_valid_mockups(categories): def get_invalid_mockups(categories): return [ { - 'name': '', - 'slug': 'repository-1', - 'language': languages.LANGUAGE_EN, - 'categories': [ - category.pk - for category in categories - ], - 'is_private': True, + "name": "", + "slug": "repository-1", + "language": languages.LANGUAGE_EN, + "categories": [category.pk for category in categories], + "is_private": True, }, { - 'name': 'Repository 2', - 'slug': '', - 'language': languages.LANGUAGE_PT, - 'categories': [ - category.pk - for category in categories - ], - 'is_private': False, + "name": "Repository 2", + "slug": "", + "language": languages.LANGUAGE_PT, + "categories": [category.pk for category in categories], + "is_private": False, }, { - 'name': 'Repository 3', - 'slug': 'repo3', - 'language': 'out', - 'categories': [ - category.pk - for category in categories - ], - 'is_private': False, + "name": "Repository 3", + "slug": "repo3", + "language": "out", + "categories": [category.pk for category in categories], + "is_private": False, }, { - 'name': 'Repository 4', - 'slug': 'repository 4', - 'language': languages.LANGUAGE_EN, - 'categories': [ - category.pk - for category in categories - ], - 'is_private': True, + "name": "Repository 4", + "slug": "repository 4", + "language": languages.LANGUAGE_EN, + "categories": [category.pk for category in categories], + "is_private": True, }, ] def create_repository_from_mockup(owner, categories, **mockup): - r = Repository.objects.create( - owner_id=owner.id, - **mockup) + r = Repository.objects.create(owner_id=owner.id, **mockup) for category in categories: r.categories.add(category) return r @@ -117,68 +96,50 @@ class CreateRepositoryAPITestCase(TestCase): def setUp(self): self.factory = RequestFactory() - self.owner, self.owner_token = create_user_and_token('owner') - self.user, self.user_token = create_user_and_token('user') - self.category = RepositoryCategory.objects.create(name='Category 1') + self.owner, self.owner_token = create_user_and_token("owner") + self.user, self.user_token = create_user_and_token("user") + self.category = RepositoryCategory.objects.create(name="Category 1") def request(self, data, token=None): - authorization_header = { - 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), - } if token else {} + authorization_header = ( + {"HTTP_AUTHORIZATION": "Token {}".format(token.key)} if token else {} + ) request = self.factory.post( - '/v2/repository/repository-info/', - data, - **authorization_header) + "/v2/repository/repository-info/", data, **authorization_header + ) - response = RepositoryViewSet.as_view({'post': 'create'})(request) + response = RepositoryViewSet.as_view({"post": "create"})(request) response.render() content_data = json.loads(response.content) - return (response, content_data,) + return (response, content_data) def test_okay(self): for mockup in get_valid_mockups([self.category]): - response, content_data = self.request( - mockup, - self.owner_token) + response, content_data = self.request(mockup, self.owner_token) - self.assertEqual( - response.status_code, - status.HTTP_201_CREATED) + self.assertEqual(response.status_code, status.HTTP_201_CREATED) - repository = self.owner.repositories.get( - uuid=content_data.get('uuid')) + repository = self.owner.repositories.get(uuid=content_data.get("uuid")) - self.assertEqual( - repository.name, - mockup.get('name')) - self.assertEqual( - repository.slug, - mockup.get('slug')) - self.assertEqual( - repository.language, - mockup.get('language')) - self.assertEqual( - repository.is_private, - mockup.get('is_private')) + self.assertEqual(repository.name, mockup.get("name")) + self.assertEqual(repository.slug, mockup.get("slug")) + self.assertEqual(repository.language, mockup.get("language")) + self.assertEqual(repository.is_private, mockup.get("is_private")) def test_invalid_data(self): for mockup in get_invalid_mockups([self.category]): - response, content_data = self.request( - mockup, - self.owner_token) + response, content_data = self.request(mockup, self.owner_token) - self.assertEqual( - response.status_code, - status.HTTP_400_BAD_REQUEST) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) class RetriveRepositoryTestCase(TestCase): def setUp(self): self.factory = RequestFactory() - self.owner, self.owner_token = create_user_and_token('owner') - self.category = RepositoryCategory.objects.create(name='Category 1') + self.owner, self.owner_token = create_user_and_token("owner") + self.category = RepositoryCategory.objects.create(name="Category 1") self.repositories = [ create_repository_from_mockup(self.owner, **mockup) @@ -186,27 +147,26 @@ def setUp(self): ] def request(self, repository, token=None): - authorization_header = { - 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), - } if token else {} + authorization_header = ( + {"HTTP_AUTHORIZATION": "Token {}".format(token.key)} if token else {} + ) request = self.factory.get( - '/v2/repository/repository-info/{}/'.format(repository.uuid), - **authorization_header) + "/v2/repository/repository-info/{}/".format(repository.uuid), + **authorization_header, + ) - response = RepositoryViewSet.as_view({'get': 'retrieve'})( - request, - uuid=repository.uuid) + response = RepositoryViewSet.as_view({"get": "retrieve"})( + request, uuid=repository.uuid + ) response.render() content_data = json.loads(response.content) - return (response, content_data,) + return (response, content_data) def test_okay(self): for repository in self.repositories: response, content_data = self.request(repository, self.owner_token) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) + self.assertEqual(response.status_code, status.HTTP_200_OK) def test_private_repository(self): for repository in self.repositories: @@ -214,16 +174,18 @@ def test_private_repository(self): self.assertEqual( response.status_code, status.HTTP_401_UNAUTHORIZED - if repository.is_private else status.HTTP_200_OK) + if repository.is_private + else status.HTTP_200_OK, + ) class UpdateRepositoryTestCase(TestCase): def setUp(self): self.factory = RequestFactory() - self.owner, self.owner_token = create_user_and_token('owner') - self.user, self.user_token = create_user_and_token('user') - self.category = RepositoryCategory.objects.create(name='Category 1') + self.owner, self.owner_token = create_user_and_token("owner") + self.user, self.user_token = create_user_and_token("user") + self.category = RepositoryCategory.objects.create(name="Category 1") self.repositories = [ create_repository_from_mockup(self.owner, **mockup) @@ -231,49 +193,43 @@ def setUp(self): ] def request(self, repository, data={}, token=None): - authorization_header = { - 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), - } if token else {} + authorization_header = ( + {"HTTP_AUTHORIZATION": "Token {}".format(token.key)} if token else {} + ) request = self.factory.patch( - '/v2/repository/repository-info/{}/'.format(repository.uuid), + "/v2/repository/repository-info/{}/".format(repository.uuid), self.factory._encode_data(data, MULTIPART_CONTENT), MULTIPART_CONTENT, - **authorization_header) + **authorization_header, + ) - response = RepositoryViewSet.as_view({'patch': 'update'})( - request, - uuid=repository.uuid, - partial=True) + response = RepositoryViewSet.as_view({"patch": "update"})( + request, uuid=repository.uuid, partial=True + ) response.render() content_data = json.loads(response.content) - return (response, content_data,) + return (response, content_data) def test_okay_update_name(self): for repository in self.repositories: response, content_data = self.request( repository, - { - 'name': 'Repository {}'.format(repository.uuid), - }, - self.owner_token) + {"name": "Repository {}".format(repository.uuid)}, + self.owner_token, + ) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) + self.assertEqual(response.status_code, status.HTTP_200_OK) def test_unauthorized(self): for repository in self.repositories: response, content_data = self.request( repository, - { - 'name': 'Repository {}'.format(repository.uuid), - }, - self.user_token) + {"name": "Repository {}".format(repository.uuid)}, + self.user_token, + ) - self.assertEqual( - response.status_code, - status.HTTP_403_FORBIDDEN) + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) class RepositoryAuthorizationTestCase(TestCase): @@ -281,8 +237,8 @@ def setUp(self): self.factory = RequestFactory() self.user, self.user_token = create_user_and_token() - self.owner, self.owner_token = create_user_and_token('owner') - self.category = RepositoryCategory.objects.create(name='Category 1') + self.owner, self.owner_token = create_user_and_token("owner") + self.category = RepositoryCategory.objects.create(name="Category 1") self.repositories = [ create_repository_from_mockup(self.owner, **mockup) @@ -290,20 +246,21 @@ def setUp(self): ] def request(self, repository, token=None): - authorization_header = { - 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), - } if token else {} + authorization_header = ( + {"HTTP_AUTHORIZATION": "Token {}".format(token.key)} if token else {} + ) request = self.factory.get( - '/v2/repository/repository-info/{}/'.format(repository.uuid), - **authorization_header) + "/v2/repository/repository-info/{}/".format(repository.uuid), + **authorization_header, + ) - response = RepositoryViewSet.as_view({'get': 'retrieve'})( - request, - uuid=repository.uuid) + response = RepositoryViewSet.as_view({"get": "retrieve"})( + request, uuid=repository.uuid + ) response.render() content_data = json.loads(response.content) - return (response, content_data,) + return (response, content_data) def test_authorization_without_user(self): for repository in self.repositories: @@ -311,18 +268,22 @@ def test_authorization_without_user(self): if repository.is_private: continue response, content_data = self.request(repository) - self.assertIsNone(content_data.get('authorization')) + self.assertIsNone(content_data.get("authorization")) def test_authorization_with_user(self): for repository in self.repositories: - user, user_token = (self.owner, self.owner_token) \ - if repository.is_private else (self.user, self.user_token) + user, user_token = ( + (self.owner, self.owner_token) + if repository.is_private + else (self.user, self.user_token) + ) response, content_data = self.request(repository, user_token) - authorization = content_data.get('authorization') + authorization = content_data.get("authorization") self.assertIsNotNone(authorization) self.assertEqual( - authorization.get('uuid'), - str(repository.get_user_authorization(user).uuid)) + authorization.get("uuid"), + str(repository.get_user_authorization(user).uuid), + ) class RepositoryAvailableRequestAuthorizationTestCase(TestCase): @@ -330,1148 +291,880 @@ def setUp(self): self.factory = RequestFactory() self.user, self.user_token = create_user_and_token() - self.owner, self.owner_token = create_user_and_token('owner') + self.owner, self.owner_token = create_user_and_token("owner") self.repository = Repository.objects.create( owner=self.owner, - name='Testing', - slug='test', - language=languages.LANGUAGE_EN) + name="Testing", + slug="test", + language=languages.LANGUAGE_EN, + ) def request(self, repository, token=None): - authorization_header = { - 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), - } if token else {} + authorization_header = ( + {"HTTP_AUTHORIZATION": "Token {}".format(token.key)} if token else {} + ) request = self.factory.get( - '/v2/repository/repository-info/{}/'.format(repository.uuid), - **authorization_header) + "/v2/repository/repository-info/{}/".format(repository.uuid), + **authorization_header, + ) - response = RepositoryViewSet.as_view({'get': 'retrieve'})( - request, - uuid=repository.uuid) + response = RepositoryViewSet.as_view({"get": "retrieve"})( + request, uuid=repository.uuid + ) response.render() content_data = json.loads(response.content) - return (response, content_data,) + return (response, content_data) def test_owner_ever_false(self): - response, content_data = self.request( - self.repository, - self.owner_token) + response, content_data = self.request(self.repository, self.owner_token) available_request_authorization = content_data.get( - 'available_request_authorization') + "available_request_authorization" + ) self.assertFalse(available_request_authorization) def test_user_available(self): - response, content_data = self.request( - self.repository, - self.user_token) + response, content_data = self.request(self.repository, self.user_token) available_request_authorization = content_data.get( - 'available_request_authorization') + "available_request_authorization" + ) self.assertTrue(available_request_authorization) def test_false_when_request(self): RequestRepositoryAuthorization.objects.create( - user=self.user, - repository=self.repository, - text='r') - response, content_data = self.request( - self.repository, - self.user_token) + user=self.user, repository=self.repository, text="r" + ) + response, content_data = self.request(self.repository, self.user_token) available_request_authorization = content_data.get( - 'available_request_authorization') + "available_request_authorization" + ) self.assertFalse(available_request_authorization) class IntentsInRepositorySerializerTestCase(TestCase): def setUp(self): - self.owner, self.owner_token = create_user_and_token('owner') + self.owner, self.owner_token = create_user_and_token("owner") self.repository = Repository.objects.create( owner=self.owner, - name='Testing', - slug='test', - language=languages.LANGUAGE_EN) + name="Testing", + slug="test", + language=languages.LANGUAGE_EN, + ) RepositoryExample.objects.create( repository_update=self.repository.current_update(), - text='hi', - intent='greet') + text="hi", + intent="greet", + ) def test_count_1(self): repository_data = RepositorySerializer(self.repository).data - intent = repository_data.get('intents')[0] - self.assertEqual(intent.get('examples__count'), 1) + intent = repository_data.get("intents")[0] + self.assertEqual(intent.get("examples__count"), 1) def test_example_deleted(self): example = RepositoryExample.objects.create( repository_update=self.repository.current_update(), - text='hi', - intent='greet') + text="hi", + intent="greet", + ) repository_data = RepositorySerializer(self.repository).data - intent = repository_data.get('intents')[0] - self.assertEqual(intent.get('examples__count'), 2) + intent = repository_data.get("intents")[0] + self.assertEqual(intent.get("examples__count"), 2) example.delete() repository_data = RepositorySerializer(self.repository).data - intent = repository_data.get('intents')[0] - self.assertEqual(intent.get('examples__count'), 1) + intent = repository_data.get("intents")[0] + self.assertEqual(intent.get("examples__count"), 1) class RepositoriesViewSetTestCase(TestCase): def setUp(self): self.factory = RequestFactory() - self.owner, self.owner_token = create_user_and_token('owner') - self.category_1 = RepositoryCategory.objects.create(name='Category 1') - self.category_2 = RepositoryCategory.objects.create(name='Category 2') + self.owner, self.owner_token = create_user_and_token("owner") + self.category_1 = RepositoryCategory.objects.create(name="Category 1") + self.category_2 = RepositoryCategory.objects.create(name="Category 2") self.repositories = [ create_repository_from_mockup(self.owner, **mockup) for mockup in get_valid_mockups([self.category_1]) ] self.public_repositories = list( - filter( - lambda r: not r.is_private, - self.repositories, - ) + filter(lambda r: not r.is_private, self.repositories) ) def request(self, data={}, token=None): - authorization_header = { - 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), - } if token else {} - request = self.factory.get( - '/v2/repositories/', - data, - **authorization_header, + authorization_header = ( + {"HTTP_AUTHORIZATION": "Token {}".format(token.key)} if token else {} ) - response = RepositoriesViewSet.as_view({'get': 'list'})(request) + request = self.factory.get("/v2/repositories/", data, **authorization_header) + response = RepositoriesViewSet.as_view({"get": "list"})(request) response.render() content_data = json.loads(response.content) - return (response, content_data,) + return (response, content_data) def test_count(self): public_repositories_length = len(self.public_repositories) response, content_data = self.request() - self.assertEqual( - content_data.get('count'), - public_repositories_length, - ) + self.assertEqual(content_data.get("count"), public_repositories_length) def test_name_filter(self): - response, content_data = self.request({ - 'name': self.public_repositories[0].name, - }) - self.assertEqual( - content_data.get('count'), - 1, - ) - response, content_data = self.request({ - 'name': 'abc', - }) - self.assertEqual( - content_data.get('count'), - 0, + response, content_data = self.request( + {"name": self.public_repositories[0].name} ) + self.assertEqual(content_data.get("count"), 1) + response, content_data = self.request({"name": "abc"}) + self.assertEqual(content_data.get("count"), 0) def test_category_filter(self): - response, content_data = self.request({ - 'categories': [ - self.category_1.id, - ], - }) - self.assertEqual( - content_data.get('count'), - 1, - ) - response, content_data = self.request({ - 'categories': [ - self.category_2.id, - ], - }) - self.assertEqual( - content_data.get('count'), - 0, - ) + response, content_data = self.request({"categories": [self.category_1.id]}) + self.assertEqual(content_data.get("count"), 1) + response, content_data = self.request({"categories": [self.category_2.id]}) + self.assertEqual(content_data.get("count"), 0) class RepositoriesLanguageFilterTestCase(TestCase): def setUp(self): self.factory = RequestFactory() - self.owner, self.owner_token = create_user_and_token('owner') + self.owner, self.owner_token = create_user_and_token("owner") self.repository_en_1 = Repository.objects.create( owner=self.owner, - name='Testing en_1', - slug='test en_1', - language=languages.LANGUAGE_EN) + name="Testing en_1", + slug="test en_1", + language=languages.LANGUAGE_EN, + ) self.repository_en_2 = Repository.objects.create( owner=self.owner, - name='Testing en_2', - slug='en_2', - language=languages.LANGUAGE_EN) + name="Testing en_2", + slug="en_2", + language=languages.LANGUAGE_EN, + ) self.repository_pt = Repository.objects.create( owner=self.owner, - name='Testing pt', - slug='pt', - language=languages.LANGUAGE_PT) + name="Testing pt", + slug="pt", + language=languages.LANGUAGE_PT, + ) def request(self, data={}, token=None): - authorization_header = { - 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), - } if token else {} - request = self.factory.get( - '/v2/repositories/', - data, - **authorization_header, + authorization_header = ( + {"HTTP_AUTHORIZATION": "Token {}".format(token.key)} if token else {} ) - response = RepositoriesViewSet.as_view({'get': 'list'})(request) + request = self.factory.get("/v2/repositories/", data, **authorization_header) + response = RepositoriesViewSet.as_view({"get": "list"})(request) response.render() content_data = json.loads(response.content) - return (response, content_data,) + return (response, content_data) def test_main_language(self): - response, content_data = self.request({ - 'language': languages.LANGUAGE_EN, - }) - self.assertEqual( - response.status_code, - status.HTTP_200_OK, - ) - self.assertEqual( - content_data.get('count'), - 2, - ) - response, content_data = self.request({ - 'language': languages.LANGUAGE_PT, - }) - self.assertEqual( - response.status_code, - status.HTTP_200_OK, - ) - self.assertEqual( - content_data.get('count'), - 1, - ) + response, content_data = self.request({"language": languages.LANGUAGE_EN}) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(content_data.get("count"), 2) + response, content_data = self.request({"language": languages.LANGUAGE_PT}) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(content_data.get("count"), 1) def test_example_language(self): language = languages.LANGUAGE_ES example = RepositoryExample.objects.create( repository_update=self.repository_en_1.current_update(language), - text='hi', - intent='greet') - response, content_data = self.request({ - 'language': language, - }) - self.assertEqual( - response.status_code, - status.HTTP_200_OK, - ) - self.assertEqual( - content_data.get('count'), - 1, + text="hi", + intent="greet", ) + response, content_data = self.request({"language": language}) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(content_data.get("count"), 1) example.delete() - response, content_data = self.request({ - 'language': language, - }) - self.assertEqual( - response.status_code, - status.HTTP_200_OK, - ) - self.assertEqual( - content_data.get('count'), - 0, - ) + response, content_data = self.request({"language": language}) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(content_data.get("count"), 0) def test_translated_example(self): language = languages.LANGUAGE_ES example = RepositoryExample.objects.create( repository_update=self.repository_en_1.current_update(), - text='hi', - intent='greet') - translated = RepositoryTranslatedExample.objects.create( - original_example=example, - language=language, - text='hola' + text="hi", + intent="greet", ) - response, content_data = self.request({ - 'language': language, - }) - self.assertEqual( - response.status_code, - status.HTTP_200_OK, - ) - self.assertEqual( - content_data.get('count'), - 1, + translated = RepositoryTranslatedExample.objects.create( + original_example=example, language=language, text="hola" ) + response, content_data = self.request({"language": language}) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(content_data.get("count"), 1) translated.delete() - response, content_data = self.request({ - 'language': language, - }) - self.assertEqual( - response.status_code, - status.HTTP_200_OK, - ) - self.assertEqual( - content_data.get('count'), - 0, - ) + response, content_data = self.request({"language": language}) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(content_data.get("count"), 0) class ListRepositoryVoteTestCase(TestCase): def setUp(self): self.factory = RequestFactory() - self.owner, self.owner_token = create_user_and_token('owner') + self.owner, self.owner_token = create_user_and_token("owner") self.user, self.token = create_user_and_token() self.repository = Repository.objects.create( owner=self.owner, - name='Testing', - slug='test', - language=languages.LANGUAGE_EN + name="Testing", + slug="test", + language=languages.LANGUAGE_EN, ) self.repository_votes = RepositoryVote.objects.create( - user=self.owner, - repository=self.repository + user=self.owner, repository=self.repository ) def request(self, param, value, token): - authorization_header = { - 'HTTP_AUTHORIZATION': 'Token {}'.format(token), - } + authorization_header = {"HTTP_AUTHORIZATION": "Token {}".format(token)} request = self.factory.get( - '/v2/repository-votes/?{}={}'.format( - param, - value - ), **authorization_header + "/v2/repository-votes/?{}={}".format(param, value), **authorization_header ) - response = RepositoryVotesViewSet.as_view({'get': 'list'})( - request, - repository=self.repository.uuid + response = RepositoryVotesViewSet.as_view({"get": "list"})( + request, repository=self.repository.uuid ) response.render() content_data = json.loads(response.content) - return (response, content_data,) + return (response, content_data) def test_repository_okay(self): response, content_data = self.request( - 'repository', - self.repository.uuid, - self.owner_token.key + "repository", self.repository.uuid, self.owner_token.key ) - self.assertEqual(content_data['count'], 1) - self.assertEqual(len(content_data['results']), 1) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) + self.assertEqual(content_data["count"], 1) + self.assertEqual(len(content_data["results"]), 1) + self.assertEqual(response.status_code, status.HTTP_200_OK) def test_private_repository_okay(self): - response, content_data = self.request( - 'repository', - self.repository.uuid, - '' - ) - self.assertEqual( - response.status_code, - status.HTTP_401_UNAUTHORIZED) + response, content_data = self.request("repository", self.repository.uuid, "") + self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED) def test_user_okay(self): response, content_data = self.request( - 'user', - self.owner.nickname, - self.owner_token.key + "user", self.owner.nickname, self.owner_token.key ) - self.assertEqual(content_data['count'], 1) - self.assertEqual(len(content_data['results']), 1) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) + self.assertEqual(content_data["count"], 1) + self.assertEqual(len(content_data["results"]), 1) + self.assertEqual(response.status_code, status.HTTP_200_OK) def test_private_user_okay(self): - response, content_data = self.request( - 'user', - self.owner.nickname, - '' - ) - self.assertEqual( - response.status_code, - status.HTTP_401_UNAUTHORIZED) + response, content_data = self.request("user", self.owner.nickname, "") + self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED) class NewRepositoryVoteTestCase(TestCase): def setUp(self): self.factory = RequestFactory() - self.owner, self.owner_token = create_user_and_token('owner') + self.owner, self.owner_token = create_user_and_token("owner") self.user, self.token = create_user_and_token() self.repository = Repository.objects.create( owner=self.owner, - name='Testing', - slug='test', - language=languages.LANGUAGE_EN + name="Testing", + slug="test", + language=languages.LANGUAGE_EN, ) def request(self, data, token): - authorization_header = { - 'HTTP_AUTHORIZATION': 'Token {}'.format(token), - } + authorization_header = {"HTTP_AUTHORIZATION": "Token {}".format(token)} request = self.factory.post( - '/v2/repository-votes/', + "/v2/repository-votes/", json.dumps(data), - content_type='application/json', - **authorization_header + content_type="application/json", + **authorization_header, ) - response = RepositoryVotesViewSet.as_view({'post': 'create'})( - request, - repository=self.repository.uuid + response = RepositoryVotesViewSet.as_view({"post": "create"})( + request, repository=self.repository.uuid ) response.render() content_data = json.loads(response.content) - return (response, content_data,) + return (response, content_data) def test_okay(self): response, content_data = self.request( - { - 'repository': str(self.repository.uuid) - }, self.owner_token.key) - self.assertEqual(content_data['user'], self.owner.id) - self.assertEqual( - content_data['repository'], - str(self.repository.uuid) - ) - self.assertEqual( - response.status_code, - status.HTTP_201_CREATED + {"repository": str(self.repository.uuid)}, self.owner_token.key ) + self.assertEqual(content_data["user"], self.owner.id) + self.assertEqual(content_data["repository"], str(self.repository.uuid)) + self.assertEqual(response.status_code, status.HTTP_201_CREATED) def test_private_okay(self): response, content_data = self.request( - { - 'repository': str(self.repository.uuid) - }, '') - - self.assertEqual( - response.status_code, - status.HTTP_401_UNAUTHORIZED + {"repository": str(self.repository.uuid)}, "" ) + self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED) + class DestroyRepositoryVoteTestCase(TestCase): def setUp(self): self.factory = RequestFactory() - self.owner, self.owner_token = create_user_and_token('owner') + self.owner, self.owner_token = create_user_and_token("owner") self.user, self.token = create_user_and_token() self.repository = Repository.objects.create( owner=self.owner, - name='Testing', - slug='test', - language=languages.LANGUAGE_EN + name="Testing", + slug="test", + language=languages.LANGUAGE_EN, ) self.repository_votes = RepositoryVote.objects.create( - user=self.owner, - repository=self.repository + user=self.owner, repository=self.repository ) def request(self, token): - authorization_header = { - 'HTTP_AUTHORIZATION': 'Token {}'.format(token), - } + authorization_header = {"HTTP_AUTHORIZATION": "Token {}".format(token)} request = self.factory.delete( - '/v2/repository-votes/{}/'.format(str(self.repository.uuid)), - **authorization_header + "/v2/repository-votes/{}/".format(str(self.repository.uuid)), + **authorization_header, ) - response = RepositoryVotesViewSet.as_view({'delete': 'destroy'})( - request, - repository=self.repository.uuid + response = RepositoryVotesViewSet.as_view({"delete": "destroy"})( + request, repository=self.repository.uuid ) response.render() return response def test_okay(self): response = self.request(self.owner_token.key) - self.assertEqual( - response.status_code, - status.HTTP_204_NO_CONTENT - ) + self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) def test_private_okay(self): - response = self.request('') + response = self.request("") - self.assertEqual( - response.status_code, - status.HTTP_401_UNAUTHORIZED - ) + self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED) class ListRepositoryContributionsTestCase(TestCase): def setUp(self): self.factory = RequestFactory() - self.owner, self.owner_token = create_user_and_token('owner') + self.owner, self.owner_token = create_user_and_token("owner") self.user, self.token = create_user_and_token() self.repository = Repository.objects.create( owner=self.owner, - name='Testing', - slug='test', - language=languages.LANGUAGE_EN - ) - - text = 'I can contribute' - self.repository_request_auth = \ - RequestRepositoryAuthorization.objects.create( - user=self.user, - repository=self.repository, - approved_by=self.owner, - text=text - ) + name="Testing", + slug="test", + language=languages.LANGUAGE_EN, + ) - self.repository_auth = RepositoryAuthorization.objects.create( + text = "I can contribute" + self.repository_request_auth = RequestRepositoryAuthorization.objects.create( user=self.user, repository=self.repository, - role=0 + approved_by=self.owner, + text=text, + ) + + self.repository_auth = RepositoryAuthorization.objects.create( + user=self.user, repository=self.repository, role=0 ) def request(self): request = self.factory.get( - '/v2/repositories-contributions/?nickname={}'.format( - self.user.nickname - ) + "/v2/repositories-contributions/?nickname={}".format(self.user.nickname) ) - response = RepositoriesContributionsViewSet.as_view({'get': 'list'})( - request, - nickname=self.user.nickname + response = RepositoriesContributionsViewSet.as_view({"get": "list"})( + request, nickname=self.user.nickname ) response.render() content_data = json.loads(response.content) - return (response, content_data,) + return (response, content_data) def test_okay(self): response, content_data = self.request() - self.assertEqual( - response.status_code, - status.HTTP_200_OK - ) - self.assertEqual( - content_data['count'], - 1 - ) - self.assertEqual( - len(content_data['results']), - 1 - ) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(content_data["count"], 1) + self.assertEqual(len(content_data["results"]), 1) class CategoriesTestCase(TestCase): def setUp(self): self.factory = RequestFactory() - self.category = RepositoryCategory.objects.create(name='Category 1') + self.category = RepositoryCategory.objects.create(name="Category 1") self.business_category = RepositoryCategory.objects.create( - name='Business', - icon='business') + name="Business", icon="business" + ) def request(self): - request = self.factory.get('/v2/repository/categories/') - response = RepositoryCategoriesView.as_view( - {'get': 'list'})(request) + request = self.factory.get("/v2/repository/categories/") + response = RepositoryCategoriesView.as_view({"get": "list"})(request) response.render() content_data = json.loads(response.content) - return (response, content_data,) + return (response, content_data) def test_default_category_icon(self): response, content_data = self.request() - self.assertEqual( - content_data[0].get('id'), - self.category.id) - self.assertEqual( - content_data[0].get('icon'), - 'botinho') + self.assertEqual(content_data[0].get("id"), self.category.id) + self.assertEqual(content_data[0].get("icon"), "botinho") def test_custom_category_icon(self): response, content_data = self.request() - self.assertEqual( - content_data[1].get('id'), - self.business_category.id) - self.assertEqual( - content_data[1].get('icon'), - self.business_category.icon) + self.assertEqual(content_data[1].get("id"), self.business_category.id) + self.assertEqual(content_data[1].get("icon"), self.business_category.icon) class SearchRepositoriesTestCase(TestCase): def setUp(self): self.factory = RequestFactory() - self.owner, self.owner_token = create_user_and_token('owner') + self.owner, self.owner_token = create_user_and_token("owner") self.user, self.user_token = create_user_and_token() - self.category = RepositoryCategory.objects.create( - name='ID') + self.category = RepositoryCategory.objects.create(name="ID") self.repository = Repository.objects.create( owner=self.owner, - name='Testing', - slug='test', - language=languages.LANGUAGE_EN) + name="Testing", + slug="test", + language=languages.LANGUAGE_EN, + ) self.repository.categories.add(self.category) def request(self, nickname): request = self.factory.get( - '/v2/repository/search-repositories/?nickname={}'.format(nickname) + "/v2/repository/search-repositories/?nickname={}".format(nickname) + ) + response = SearchRepositoriesViewSet.as_view({"get": "list"})( + request, nickname=nickname ) - response = SearchRepositoriesViewSet.as_view( - {'get': 'list'} - )(request, nickname=nickname) response.render() content_data = json.loads(response.content) - return (response, content_data,) + return (response, content_data) def test_okay(self): - response, content_data = self.request('owner') + response, content_data = self.request("owner") self.assertEqual(response.status_code, 200) + self.assertEqual(content_data.get("count"), 1) self.assertEqual( - content_data.get('count'), - 1) - self.assertEqual( - uuid.UUID(content_data.get('results')[0].get('uuid')), - self.repository.uuid) + uuid.UUID(content_data.get("results")[0].get("uuid")), self.repository.uuid + ) def test_empty_with_user_okay(self): - response, content_data = self.request('fake') + response, content_data = self.request("fake") self.assertEqual(response.status_code, 200) - self.assertEqual( - content_data.get('count'), - 0) + self.assertEqual(content_data.get("count"), 0) def test_empty_without_user_okay(self): - response, content_data = self.request('') + response, content_data = self.request("") self.assertEqual(response.status_code, 200) - self.assertEqual( - content_data.get('count'), - 0) + self.assertEqual(content_data.get("count"), 0) class ListAuthorizationTestCase(TestCase): def setUp(self): self.factory = RequestFactory() - self.owner, self.owner_token = create_user_and_token('owner') + self.owner, self.owner_token = create_user_and_token("owner") self.user, self.user_token = create_user_and_token() self.repository = Repository.objects.create( owner=self.owner, - name='Testing', - slug='test', - language=languages.LANGUAGE_EN) + name="Testing", + slug="test", + language=languages.LANGUAGE_EN, + ) self.user_auth = self.repository.get_user_authorization(self.user) self.user_auth.role = RepositoryAuthorization.ROLE_CONTRIBUTOR self.user_auth.save() def request(self, repository, token): - authorization_header = { - 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), - } + authorization_header = {"HTTP_AUTHORIZATION": "Token {}".format(token.key)} request = self.factory.get( - '/v2/repository/authorizations/', - { - 'repository': repository.uuid, - }, - **authorization_header) - response = RepositoryAuthorizationViewSet.as_view( - {'get': 'list'})(request) + "/v2/repository/authorizations/", + {"repository": repository.uuid}, + **authorization_header, + ) + response = RepositoryAuthorizationViewSet.as_view({"get": "list"})(request) response.render() content_data = json.loads(response.content) - return (response, content_data,) + return (response, content_data) def test_okay(self): - response, content_data = self.request( - self.repository, - self.owner_token) + response, content_data = self.request(self.repository, self.owner_token) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) + self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual( - content_data.get('count'), - 1) + self.assertEqual(content_data.get("count"), 1) - self.assertEqual( - content_data.get('results')[0].get('user'), - self.user.id) + self.assertEqual(content_data.get("results")[0].get("user"), self.user.id) def test_user_forbidden(self): - response, content_data = self.request( - self.repository, - self.user_token) + response, content_data = self.request(self.repository, self.user_token) - self.assertEqual( - response.status_code, - status.HTTP_403_FORBIDDEN) + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) class UpdateAuthorizationRoleTestCase(TestCase): def setUp(self): self.factory = RequestFactory() - self.owner, self.owner_token = create_user_and_token('owner') + self.owner, self.owner_token = create_user_and_token("owner") self.user, self.user_token = create_user_and_token() self.repository = Repository.objects.create( owner=self.owner, - name='Testing', - slug='test', - language=languages.LANGUAGE_EN) + name="Testing", + slug="test", + language=languages.LANGUAGE_EN, + ) def request(self, repository, token, user, data): - authorization_header = { - 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), - } + authorization_header = {"HTTP_AUTHORIZATION": "Token {}".format(token.key)} request = self.factory.patch( - '/v2/repository/authorizations/{}/{}/'.format( - repository.uuid, user.nickname), + "/v2/repository/authorizations/{}/{}/".format( + repository.uuid, user.nickname + ), self.factory._encode_data(data, MULTIPART_CONTENT), MULTIPART_CONTENT, - **authorization_header) - view = RepositoryAuthorizationViewSet.as_view( - {'patch': 'update'}) + **authorization_header, + ) + view = RepositoryAuthorizationViewSet.as_view({"patch": "update"}) response = view( - request, - repository__uuid=repository.uuid, - user__nickname=user.nickname) + request, repository__uuid=repository.uuid, user__nickname=user.nickname + ) response.render() content_data = json.loads(response.content) - return (response, content_data,) + return (response, content_data) def test_okay(self): response, content_data = self.request( self.repository, self.owner_token, self.user, - { - 'role': RepositoryAuthorization.ROLE_CONTRIBUTOR, - }) + {"role": RepositoryAuthorization.ROLE_CONTRIBUTOR}, + ) + self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual( - response.status_code, - status.HTTP_200_OK) - self.assertEqual( - content_data.get('role'), - RepositoryAuthorization.ROLE_CONTRIBUTOR) + content_data.get("role"), RepositoryAuthorization.ROLE_CONTRIBUTOR + ) user_authorization = self.repository.get_user_authorization(self.user) self.assertEqual( - user_authorization.role, - RepositoryAuthorization.ROLE_CONTRIBUTOR) + user_authorization.role, RepositoryAuthorization.ROLE_CONTRIBUTOR + ) def test_forbidden(self): response, content_data = self.request( self.repository, self.user_token, self.user, - { - 'role': RepositoryAuthorization.ROLE_CONTRIBUTOR, - }) + {"role": RepositoryAuthorization.ROLE_CONTRIBUTOR}, + ) - self.assertEqual( - response.status_code, - status.HTTP_403_FORBIDDEN) + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) def test_owner_can_t_set_your_role(self): response, content_data = self.request( self.repository, self.owner_token, self.owner, - { - 'role': RepositoryAuthorization.ROLE_CONTRIBUTOR, - }) + {"role": RepositoryAuthorization.ROLE_CONTRIBUTOR}, + ) - self.assertEqual( - response.status_code, - status.HTTP_403_FORBIDDEN) + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) class RepositoryAuthorizationRequestsTestCase(TestCase): def setUp(self): self.factory = RequestFactory() - self.owner, self.owner_token = create_user_and_token('owner') - self.admin, self.admin_token = create_user_and_token('admin') + self.owner, self.owner_token = create_user_and_token("owner") + self.admin, self.admin_token = create_user_and_token("admin") self.user, self.user_token = create_user_and_token() self.repository = Repository.objects.create( owner=self.owner, - name='Testing', - slug='test', - language=languages.LANGUAGE_EN) + name="Testing", + slug="test", + language=languages.LANGUAGE_EN, + ) RequestRepositoryAuthorization.objects.create( - user=self.user, - repository=self.repository, - text='I can contribute') + user=self.user, repository=self.repository, text="I can contribute" + ) admin_autho = self.repository.get_user_authorization(self.admin) admin_autho.role = RepositoryAuthorization.ROLE_ADMIN admin_autho.save() def request(self, data, token=None): - authorization_header = { - 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), - } if token else {} + authorization_header = ( + {"HTTP_AUTHORIZATION": "Token {}".format(token.key)} if token else {} + ) request = self.factory.get( - '/v2/repository/authorization-requests/', - data, - **authorization_header) - response = RepositoryAuthorizationRequestsViewSet.as_view( - {'get': 'list'})(request) + "/v2/repository/authorization-requests/", data, **authorization_header + ) + response = RepositoryAuthorizationRequestsViewSet.as_view({"get": "list"})( + request + ) response.render() content_data = json.loads(response.content) - return (response, content_data,) + return (response, content_data) def test_okay(self): - response, content_data = self.request({ - 'repository_uuid': self.repository.uuid, - }, self.owner_token) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) - self.assertEqual( - content_data.get('count'), - 1) + response, content_data = self.request( + {"repository_uuid": self.repository.uuid}, self.owner_token + ) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(content_data.get("count"), 1) def test_admin_okay(self): - response, content_data = self.request({ - 'repository_uuid': self.repository.uuid, - }, self.admin_token) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) - self.assertEqual( - content_data.get('count'), - 1) + response, content_data = self.request( + {"repository_uuid": self.repository.uuid}, self.admin_token + ) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(content_data.get("count"), 1) def test_repository_uuid_empty(self): response, content_data = self.request({}, self.owner_token) - self.assertEqual( - response.status_code, - status.HTTP_400_BAD_REQUEST) - self.assertEqual( - len(content_data.get('repository_uuid')), - 1) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + self.assertEqual(len(content_data.get("repository_uuid")), 1) def test_forbidden(self): - response, content_data = self.request({ - 'repository_uuid': self.repository.uuid, - }, self.user_token) - self.assertEqual( - response.status_code, - status.HTTP_403_FORBIDDEN) + response, content_data = self.request( + {"repository_uuid": self.repository.uuid}, self.user_token + ) + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) class RequestAuthorizationTestCase(TestCase): def setUp(self): self.factory = RequestFactory() - self.owner, self.owner_token = create_user_and_token('owner') + self.owner, self.owner_token = create_user_and_token("owner") self.user, self.token = create_user_and_token() self.repository = Repository.objects.create( owner=self.owner, - name='Testing', - slug='test', - language=languages.LANGUAGE_EN) + name="Testing", + slug="test", + language=languages.LANGUAGE_EN, + ) def request(self, data, token=None): - authorization_header = { - 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), - } if token else {} + authorization_header = ( + {"HTTP_AUTHORIZATION": "Token {}".format(token.key)} if token else {} + ) request = self.factory.post( - '/v2/repository/authorization-requests/', - data, - **authorization_header) - response = RepositoryAuthorizationRequestsViewSet.as_view( - {'post': 'create'})(request) + "/v2/repository/authorization-requests/", data, **authorization_header + ) + response = RepositoryAuthorizationRequestsViewSet.as_view({"post": "create"})( + request + ) response.render() content_data = json.loads(response.content) - return (response, content_data,) + return (response, content_data) def test_okay(self): - response, content_data = self.request({ - 'repository': self.repository.uuid, - 'text': 'I can contribute', - }, self.token) - self.assertEqual( - response.status_code, - status.HTTP_201_CREATED) + response, content_data = self.request( + {"repository": self.repository.uuid, "text": "I can contribute"}, self.token + ) + self.assertEqual(response.status_code, status.HTTP_201_CREATED) def test_forbidden_two_requests(self): RequestRepositoryAuthorization.objects.create( - user=self.user, - repository=self.repository, - text='I can contribute') - response, content_data = self.request({ - 'repository': self.repository.uuid, - 'text': 'I can contribute', - }, self.token) - self.assertEqual( - response.status_code, - status.HTTP_400_BAD_REQUEST) - self.assertIn( - 'non_field_errors', - content_data.keys()) + user=self.user, repository=self.repository, text="I can contribute" + ) + response, content_data = self.request( + {"repository": self.repository.uuid, "text": "I can contribute"}, self.token + ) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + self.assertIn("non_field_errors", content_data.keys()) class ReviewAuthorizationRequestTestCase(TestCase): def setUp(self): self.factory = RequestFactory() - self.owner, self.owner_token = create_user_and_token('owner') - self.admin, self.admin_token = create_user_and_token('admin') + self.owner, self.owner_token = create_user_and_token("owner") + self.admin, self.admin_token = create_user_and_token("admin") self.user, self.user_token = create_user_and_token() repository = Repository.objects.create( owner=self.owner, - name='Testing', - slug='test', - language=languages.LANGUAGE_EN) + name="Testing", + slug="test", + language=languages.LANGUAGE_EN, + ) self.ra = RequestRepositoryAuthorization.objects.create( - user=self.user, - repository=repository, - text='I can contribute') + user=self.user, repository=repository, text="I can contribute" + ) admin_autho = repository.get_user_authorization(self.admin) admin_autho.role = RepositoryAuthorization.ROLE_ADMIN admin_autho.save() def request_approve(self, ra, token=None): - authorization_header = { - 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), - } if token else {} + authorization_header = ( + {"HTTP_AUTHORIZATION": "Token {}".format(token.key)} if token else {} + ) request = self.factory.put( - '/v2/repository/authorization-requests/{}/'.format(ra.pk), + "/v2/repository/authorization-requests/{}/".format(ra.pk), self.factory._encode_data({}, MULTIPART_CONTENT), MULTIPART_CONTENT, - **authorization_header) - response = RepositoryAuthorizationRequestsViewSet.as_view( - {'put': 'update'})(request, pk=ra.pk) + **authorization_header, + ) + response = RepositoryAuthorizationRequestsViewSet.as_view({"put": "update"})( + request, pk=ra.pk + ) response.render() content_data = json.loads(response.content) - return (response, content_data,) + return (response, content_data) def request_reject(self, ra, token=None): - authorization_header = { - 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), - } if token else {} + authorization_header = ( + {"HTTP_AUTHORIZATION": "Token {}".format(token.key)} if token else {} + ) request = self.factory.delete( - '/v2/repository/authorization-requests/{}/'.format(ra.pk), - **authorization_header) + "/v2/repository/authorization-requests/{}/".format(ra.pk), + **authorization_header, + ) response = RepositoryAuthorizationRequestsViewSet.as_view( - {'delete': 'destroy'})(request, pk=ra.pk) + {"delete": "destroy"} + )(request, pk=ra.pk) response.render() return response def test_approve_okay(self): - response, content_data = self.request_approve( - self.ra, - self.owner_token) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) - self.assertEqual( - content_data.get('approved_by'), - self.owner.id) + response, content_data = self.request_approve(self.ra, self.owner_token) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(content_data.get("approved_by"), self.owner.id) def test_admin_approve_okay(self): - response, content_data = self.request_approve( - self.ra, - self.admin_token) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) - self.assertEqual( - content_data.get('approved_by'), - self.admin.id) + response, content_data = self.request_approve(self.ra, self.admin_token) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(content_data.get("approved_by"), self.admin.id) def test_approve_twice(self): self.ra.approved_by = self.owner self.ra.save() - response, content_data = self.request_approve( - self.ra, - self.owner_token) - self.assertEqual( - response.status_code, - status.HTTP_400_BAD_REQUEST) + response, content_data = self.request_approve(self.ra, self.owner_token) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) def test_approve_forbidden(self): - response, content_data = self.request_approve( - self.ra, - self.user_token) - self.assertEqual( - response.status_code, - status.HTTP_403_FORBIDDEN) + response, content_data = self.request_approve(self.ra, self.user_token) + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) def test_reject_okay(self): response = self.request_reject(self.ra, self.owner_token) - self.assertEqual( - response.status_code, - status.HTTP_204_NO_CONTENT) + self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) def test_admin_reject_okay(self): response = self.request_reject(self.ra, self.admin_token) - self.assertEqual( - response.status_code, - status.HTTP_204_NO_CONTENT) + self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) def test_reject_forbidden(self): response = self.request_reject(self.ra, self.user_token) - self.assertEqual( - response.status_code, - status.HTTP_403_FORBIDDEN) + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) class RepositoryExampleRetrieveTestCase(TestCase): def setUp(self): self.factory = RequestFactory() - self.owner, self.owner_token = create_user_and_token('owner') + self.owner, self.owner_token = create_user_and_token("owner") self.user, self.user_token = create_user_and_token() self.repository = Repository.objects.create( owner=self.owner, - name='Testing', - slug='test', - language=languages.LANGUAGE_EN) + name="Testing", + slug="test", + language=languages.LANGUAGE_EN, + ) self.example = RepositoryExample.objects.create( - repository_update=self.repository.current_update(), - text='my name is user') + repository_update=self.repository.current_update(), text="my name is user" + ) self.example_entity = RepositoryExampleEntity.objects.create( - repository_example=self.example, - start=11, - end=18, - entity='name') + repository_example=self.example, start=11, end=18, entity="name" + ) self.private_repository = Repository.objects.create( owner=self.owner, - name='Testing Private', - slug='private', + name="Testing Private", + slug="private", language=languages.LANGUAGE_EN, - is_private=True) + is_private=True, + ) self.private_example = RepositoryExample.objects.create( - repository_update=self.private_repository.current_update(), - text='hi') + repository_update=self.private_repository.current_update(), text="hi" + ) def request(self, example, token): - authorization_header = { - 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), - } + authorization_header = {"HTTP_AUTHORIZATION": "Token {}".format(token.key)} request = self.factory.get( - '/v2/repository/example/{}/'.format(example.id), - **authorization_header) - response = RepositoryExampleViewSet.as_view( - {'get': 'retrieve'})(request, pk=example.id) + "/v2/repository/example/{}/".format(example.id), **authorization_header + ) + response = RepositoryExampleViewSet.as_view({"get": "retrieve"})( + request, pk=example.id + ) response.render() content_data = json.loads(response.content) - return (response, content_data,) + return (response, content_data) def test_okay(self): - response, content_data = self.request( - self.example, - self.owner_token) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) - self.assertEqual( - content_data.get('id'), - self.example.id) + response, content_data = self.request(self.example, self.owner_token) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(content_data.get("id"), self.example.id) def test_forbidden(self): - response, content_data = self.request( - self.private_example, - self.user_token) - self.assertEqual( - response.status_code, - status.HTTP_403_FORBIDDEN) + response, content_data = self.request(self.private_example, self.user_token) + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) def test_public(self): - response, content_data = self.request( - self.example, - self.user_token) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) - self.assertEqual( - content_data.get('id'), - self.example.id) + response, content_data = self.request(self.example, self.user_token) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(content_data.get("id"), self.example.id) def test_list_entities(self): - response, content_data = self.request( - self.example, - self.owner_token) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) - self.assertEqual( - len(content_data.get('entities')), - 1) + response, content_data = self.request(self.example, self.owner_token) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(len(content_data.get("entities")), 1) def test_entity_has_label(self): - response, content_data = self.request( - self.example, - self.owner_token) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) - entity = content_data.get('entities')[0] - self.assertIn( - 'label', - entity.keys()) + response, content_data = self.request(self.example, self.owner_token) + self.assertEqual(response.status_code, status.HTTP_200_OK) + entity = content_data.get("entities")[0] + self.assertIn("label", entity.keys()) def test_entity_has_valid_label(self): - label = 'subject' - self.example_entity.entity.set_label('subject') - self.example_entity.entity.save(update_fields=['label']) - response, content_data = self.request( - self.example, - self.owner_token) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) - entity = content_data.get('entities')[0] - self.assertIn( - 'label', - entity.keys()) - self.assertEqual( - entity.get('label'), - label) + label = "subject" + self.example_entity.entity.set_label("subject") + self.example_entity.entity.save(update_fields=["label"]) + response, content_data = self.request(self.example, self.owner_token) + self.assertEqual(response.status_code, status.HTTP_200_OK) + entity = content_data.get("entities")[0] + self.assertIn("label", entity.keys()) + self.assertEqual(entity.get("label"), label) class RepositoryExampleUploadTestCase(TestCase): def setUp(self): self.factory = RequestFactory() - self.owner, self.owner_token = create_user_and_token('owner') + self.owner, self.owner_token = create_user_and_token("owner") self.user, self.user_token = create_user_and_token() self.repository = Repository.objects.create( owner=self.owner, - name='Testing', - slug='test', - language=languages.LANGUAGE_EN) + name="Testing", + slug="test", + language=languages.LANGUAGE_EN, + ) def request(self, token): - authorization_header = { - 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), - } - examples = b'''[ + authorization_header = {"HTTP_AUTHORIZATION": "Token {}".format(token.key)} + examples = b"""[ { "text": "yes", "language": "en", @@ -1494,413 +1187,326 @@ def request(self, token): }], "intent": "greet" } - ]''' + ]""" uploaded_file = SimpleUploadedFile( - 'examples.json', - examples, - 'multipart/form-data' + "examples.json", examples, "multipart/form-data" ) request = self.factory.post( - '/v2/repository/example/upload_examples/', - { - 'file': uploaded_file, - 'repository': str(self.repository.uuid) - }, format='multipart', - **authorization_header) - response = RepositoryExampleViewSet.as_view( - {'post': 'upload_examples'})(request) + "/v2/repository/example/upload_examples/", + {"file": uploaded_file, "repository": str(self.repository.uuid)}, + format="multipart", + **authorization_header, + ) + response = RepositoryExampleViewSet.as_view({"post": "upload_examples"})( + request + ) response.render() content_data = json.loads(response.content) - return (response, content_data,) + return (response, content_data) def test_okay(self): response, content_data = self.request(self.owner_token) - self.assertEqual( - content_data.get('added'), - 2 - ) - self.assertEqual( - len(content_data.get('not_added')), - 0 - ) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) + self.assertEqual(content_data.get("added"), 2) + self.assertEqual(len(content_data.get("not_added")), 0) + self.assertEqual(response.status_code, status.HTTP_200_OK) def test_permission_denied(self): response, content_data = self.request(self.user_token) - self.assertEqual( - response.status_code, - status.HTTP_403_FORBIDDEN) + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) class RepositoryExampleDestroyTestCase(TestCase): def setUp(self): self.factory = RequestFactory() - self.owner, self.owner_token = create_user_and_token('owner') + self.owner, self.owner_token = create_user_and_token("owner") self.user, self.user_token = create_user_and_token() self.repository = Repository.objects.create( owner=self.owner, - name='Testing', - slug='test', - language=languages.LANGUAGE_EN) + name="Testing", + slug="test", + language=languages.LANGUAGE_EN, + ) self.example = RepositoryExample.objects.create( - repository_update=self.repository.current_update(), - text='hi') + repository_update=self.repository.current_update(), text="hi" + ) self.private_repository = Repository.objects.create( owner=self.owner, - name='Testing Private', - slug='private', + name="Testing Private", + slug="private", language=languages.LANGUAGE_EN, - is_private=True) + is_private=True, + ) self.private_example = RepositoryExample.objects.create( - repository_update=self.private_repository.current_update(), - text='hi') + repository_update=self.private_repository.current_update(), text="hi" + ) def request(self, example, token): - authorization_header = { - 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), - } + authorization_header = {"HTTP_AUTHORIZATION": "Token {}".format(token.key)} request = self.factory.delete( - '/v2/repository/example/{}/'.format(example.id), - **authorization_header) - response = RepositoryExampleViewSet.as_view( - {'delete': 'destroy'})(request, pk=example.id) + "/v2/repository/example/{}/".format(example.id), **authorization_header + ) + response = RepositoryExampleViewSet.as_view({"delete": "destroy"})( + request, pk=example.id + ) return response def test_okay(self): - response = self.request( - self.example, - self.owner_token) - self.assertEqual( - response.status_code, - status.HTTP_204_NO_CONTENT) + response = self.request(self.example, self.owner_token) + self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) def test_private_okay(self): - response = self.request( - self.private_example, - self.owner_token) - self.assertEqual( - response.status_code, - status.HTTP_204_NO_CONTENT) + response = self.request(self.private_example, self.owner_token) + self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) def test_forbidden(self): - response = self.request( - self.example, - self.user_token) - self.assertEqual( - response.status_code, - status.HTTP_403_FORBIDDEN) + response = self.request(self.example, self.user_token) + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) def test_private_forbidden(self): - response = self.request( - self.private_example, - self.user_token) - self.assertEqual( - response.status_code, - status.HTTP_403_FORBIDDEN) + response = self.request(self.private_example, self.user_token) + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) def test_already_deleted(self): self.example.delete() - response = self.request( - self.example, - self.owner_token) - self.assertEqual( - response.status_code, - status.HTTP_500_INTERNAL_SERVER_ERROR) + response = self.request(self.example, self.owner_token) + self.assertEqual(response.status_code, status.HTTP_500_INTERNAL_SERVER_ERROR) class RepositoryExampleUpdateTestCase(TestCase): def setUp(self): self.factory = RequestFactory() - self.owner, self.owner_token = create_user_and_token('owner') + self.owner, self.owner_token = create_user_and_token("owner") self.user, self.user_token = create_user_and_token() self.repository = Repository.objects.create( owner=self.owner, - name='Testing', - slug='test', - language=languages.LANGUAGE_EN) + name="Testing", + slug="test", + language=languages.LANGUAGE_EN, + ) self.example = RepositoryExample.objects.create( - repository_update=self.repository.current_update(), - text='hi') + repository_update=self.repository.current_update(), text="hi" + ) self.private_repository = Repository.objects.create( owner=self.owner, - name='Testing Private', - slug='private', + name="Testing Private", + slug="private", language=languages.LANGUAGE_EN, - is_private=True) + is_private=True, + ) self.private_example = RepositoryExample.objects.create( - repository_update=self.private_repository.current_update(), - text='hi') + repository_update=self.private_repository.current_update(), text="hi" + ) def request(self, example, token, data): - authorization_header = { - 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), - } + authorization_header = {"HTTP_AUTHORIZATION": "Token {}".format(token.key)} request = self.factory.patch( - '/v2/repository/example/{}/'.format(example.id), + "/v2/repository/example/{}/".format(example.id), json.dumps(data), - content_type='application/json', - **authorization_header) - response = RepositoryExampleViewSet.as_view( - {'patch': 'update'})(request, pk=example.id) + content_type="application/json", + **authorization_header, + ) + response = RepositoryExampleViewSet.as_view({"patch": "update"})( + request, pk=example.id + ) response.render() content_data = json.loads(response.content) - return (response, content_data,) + return (response, content_data) def test_okay(self): - text = 'teste' - intent = 'teste1234' + text = "teste" + intent = "teste1234" response, content_data = self.request( self.example, self.owner_token, - { - "repository": str(self.repository.uuid), - "text": text, - "intent": intent - } + {"repository": str(self.repository.uuid), "text": text, "intent": intent}, ) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) - self.assertEqual( - content_data.get('text'), - text) - self.assertEqual( - content_data.get('intent'), - intent) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(content_data.get("text"), text) + self.assertEqual(content_data.get("intent"), intent) def test_private_forbidden(self): response, content_data = self.request( self.private_example, self.user_token, - {"text": 'teste', "intent": 'teste1234'}) + {"text": "teste", "intent": "teste1234"}, + ) - self.assertEqual( - response.status_code, - status.HTTP_403_FORBIDDEN) + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) class NewRepositoryExampleTestCase(TestCase): def setUp(self): self.factory = RequestFactory() - self.owner, self.owner_token = create_user_and_token('owner') + self.owner, self.owner_token = create_user_and_token("owner") self.user, self.user_token = create_user_and_token() self.repository = Repository.objects.create( owner=self.owner, - name='Testing', - slug='test', - language=languages.LANGUAGE_EN) + name="Testing", + slug="test", + language=languages.LANGUAGE_EN, + ) def request(self, token, data): - authorization_header = { - 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), - } + authorization_header = {"HTTP_AUTHORIZATION": "Token {}".format(token.key)} request = self.factory.post( - '/v2/repository/example/', + "/v2/repository/example/", json.dumps(data), - content_type='application/json', - **authorization_header) - response = RepositoryExampleViewSet.as_view( - {'post': 'create'})(request) + content_type="application/json", + **authorization_header, + ) + response = RepositoryExampleViewSet.as_view({"post": "create"})(request) response.render() content_data = json.loads(response.content) - return (response, content_data,) + return (response, content_data) def test_okay(self): - text = 'hi' - intent = 'greet' + text = "hi" + intent = "greet" response, content_data = self.request( self.owner_token, { - 'repository': str(self.repository.uuid), - 'text': text, - 'intent': intent, - 'entities': [], - }) - self.assertEqual( - response.status_code, - status.HTTP_201_CREATED) - self.assertEqual( - content_data.get('text'), - text) - self.assertEqual( - content_data.get('intent'), - intent) + "repository": str(self.repository.uuid), + "text": text, + "intent": intent, + "entities": [], + }, + ) + self.assertEqual(response.status_code, status.HTTP_201_CREATED) + self.assertEqual(content_data.get("text"), text) + self.assertEqual(content_data.get("intent"), intent) def test_okay_with_language(self): - text = 'hi' - intent = 'greet' + text = "hi" + intent = "greet" language = languages.LANGUAGE_PT response, content_data = self.request( self.owner_token, { - 'repository': str(self.repository.uuid), - 'text': text, - 'language': language, - 'intent': intent, - 'entities': [], - }) - self.assertEqual( - response.status_code, - status.HTTP_201_CREATED) - self.assertEqual( - content_data.get('text'), - text) - self.assertEqual( - content_data.get('intent'), - intent) - repository_update_pk = content_data.get('repository_update') - repository_update = RepositoryUpdate.objects.get( - pk=repository_update_pk) + "repository": str(self.repository.uuid), + "text": text, + "language": language, + "intent": intent, + "entities": [], + }, + ) + self.assertEqual(response.status_code, status.HTTP_201_CREATED) + self.assertEqual(content_data.get("text"), text) + self.assertEqual(content_data.get("intent"), intent) + repository_update_pk = content_data.get("repository_update") + repository_update = RepositoryUpdate.objects.get(pk=repository_update_pk) self.assertEqual(repository_update.language, language) def test_forbidden(self): response, content_data = self.request( self.user_token, { - 'repository': str(self.repository.uuid), - 'text': 'hi', - 'intent': 'greet', - 'entities': [], - }) - self.assertEqual( - response.status_code, - status.HTTP_403_FORBIDDEN) + "repository": str(self.repository.uuid), + "text": "hi", + "intent": "greet", + "entities": [], + }, + ) + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) def test_repository_uuid_required(self): response, content_data = self.request( - self.owner_token, - { - 'text': 'hi', - 'intent': 'greet', - 'entities': [], - }) - self.assertEqual( - response.status_code, - status.HTTP_400_BAD_REQUEST) + self.owner_token, {"text": "hi", "intent": "greet", "entities": []} + ) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) def test_repository_does_not_exists(self): response, content_data = self.request( self.owner_token, { - 'repository': str(uuid.uuid4()), - 'text': 'hi', - 'intent': 'greet', - 'entities': [], - }) - self.assertEqual( - response.status_code, - status.HTTP_400_BAD_REQUEST) - self.assertIn( - 'repository', - content_data.keys()) + "repository": str(uuid.uuid4()), + "text": "hi", + "intent": "greet", + "entities": [], + }, + ) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + self.assertIn("repository", content_data.keys()) def test_invalid_repository_uuid(self): response, content_data = self.request( self.owner_token, - { - 'repository': 'invalid', - 'text': 'hi', - 'intent': 'greet', - 'entities': [], - }) - self.assertEqual( - response.status_code, - status.HTTP_400_BAD_REQUEST) + {"repository": "invalid", "text": "hi", "intent": "greet", "entities": []}, + ) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) def test_with_entities(self): response, content_data = self.request( self.owner_token, { - 'repository': str(self.repository.uuid), - 'text': 'my name is user', - 'intent': 'greet', - 'entities': [ - { - 'start': 11, - 'end': 18, - 'entity': 'name', - }, - ], - }) - self.assertEqual( - response.status_code, - status.HTTP_201_CREATED) - self.assertEqual( - len(content_data.get('entities')), - 1) + "repository": str(self.repository.uuid), + "text": "my name is user", + "intent": "greet", + "entities": [{"start": 11, "end": 18, "entity": "name"}], + }, + ) + self.assertEqual(response.status_code, status.HTTP_201_CREATED) + self.assertEqual(len(content_data.get("entities")), 1) def test_exists_example(self): - text = 'hi' - intent = 'greet' + text = "hi" + intent = "greet" response_created, content_data_created = self.request( self.owner_token, { - 'repository': str(self.repository.uuid), - 'text': text, - 'intent': intent, - 'entities': [], - }) + "repository": str(self.repository.uuid), + "text": text, + "intent": intent, + "entities": [], + }, + ) - self.assertEqual( - response_created.status_code, - status.HTTP_201_CREATED) + self.assertEqual(response_created.status_code, status.HTTP_201_CREATED) response, content_data = self.request( self.owner_token, { - 'repository': str(self.repository.uuid), - 'text': text, - 'intent': intent, - 'entities': [], - }) + "repository": str(self.repository.uuid), + "text": text, + "intent": intent, + "entities": [], + }, + ) self.assertEqual( - content_data.get('non_field_errors')[0], - 'Intention and Sentence already exists' + content_data.get("non_field_errors")[0], + "Intention and Sentence already exists", ) - self.assertEqual( - response.status_code, - status.HTTP_400_BAD_REQUEST) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) def test_with_entities_with_label(self): response, content_data = self.request( self.owner_token, { - 'repository': str(self.repository.uuid), - 'text': 'my name is user', - 'intent': 'greet', - 'entities': [ - { - 'start': 11, - 'end': 18, - 'entity': 'name', - 'label': 'subject', - }, + "repository": str(self.repository.uuid), + "text": "my name is user", + "intent": "greet", + "entities": [ + {"start": 11, "end": 18, "entity": "name", "label": "subject"} ], - }) - self.assertEqual( - response.status_code, - status.HTTP_201_CREATED) - self.assertEqual( - len(content_data.get('entities')), - 1) - id = content_data.get('id') + }, + ) + self.assertEqual(response.status_code, status.HTTP_201_CREATED) + self.assertEqual(len(content_data.get("entities")), 1) + id = content_data.get("id") repository_example = RepositoryExample.objects.get(id=id) example_entity = repository_example.entities.all()[0] self.assertIsNotNone(example_entity.entity.label) @@ -1909,418 +1515,316 @@ def test_with_entities_with_invalid_label(self): response, content_data = self.request( self.owner_token, { - 'repository': str(self.repository.uuid), - 'text': 'my name is user', - 'intent': 'greet', - 'entities': [ - { - 'start': 11, - 'end': 18, - 'entity': 'name', - 'label': 'other', - }, + "repository": str(self.repository.uuid), + "text": "my name is user", + "intent": "greet", + "entities": [ + {"start": 11, "end": 18, "entity": "name", "label": "other"} ], - }) - self.assertEqual( - response.status_code, - status.HTTP_400_BAD_REQUEST) - self.assertIn( - 'entities', - content_data.keys()) - entities_errors = content_data.get('entities') - self.assertIn( - 'label', - entities_errors[0]) + }, + ) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + self.assertIn("entities", content_data.keys()) + entities_errors = content_data.get("entities") + self.assertIn("label", entities_errors[0]) def test_with_entities_with_equal_label(self): response, content_data = self.request( self.owner_token, { - 'repository': str(self.repository.uuid), - 'text': 'my name is user', - 'intent': 'greet', - 'entities': [ - { - 'start': 11, - 'end': 18, - 'entity': 'name', - 'label': 'name', - }, + "repository": str(self.repository.uuid), + "text": "my name is user", + "intent": "greet", + "entities": [ + {"start": 11, "end": 18, "entity": "name", "label": "name"} ], - }) - self.assertEqual( - response.status_code, - status.HTTP_400_BAD_REQUEST) - self.assertIn( - 'entities', - content_data.keys()) - entities_errors = content_data.get('entities') - self.assertIn( - 'label', - entities_errors[0]) + }, + ) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + self.assertIn("entities", content_data.keys()) + entities_errors = content_data.get("entities") + self.assertIn("label", entities_errors[0]) def test_intent_or_entity_required(self): response, content_data = self.request( self.owner_token, { - 'repository': str(self.repository.uuid), - 'text': 'hi', - 'intent': '', - 'entities': [], - }) - self.assertEqual( - response.status_code, - status.HTTP_400_BAD_REQUEST) + "repository": str(self.repository.uuid), + "text": "hi", + "intent": "", + "entities": [], + }, + ) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) def test_entity_with_special_char(self): response, content_data = self.request( self.owner_token, { - 'repository': str(self.repository.uuid), - 'text': 'my name is user', - 'intent': '', - 'entities': [ - { - 'start': 11, - 'end': 18, - 'entity': 'nam&', - }, - ], - }) - self.assertEqual( - response.status_code, - status.HTTP_400_BAD_REQUEST) - self.assertEqual( - len(content_data.get('entities')), - 1) + "repository": str(self.repository.uuid), + "text": "my name is user", + "intent": "", + "entities": [{"start": 11, "end": 18, "entity": "nam&"}], + }, + ) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + self.assertEqual(len(content_data.get("entities")), 1) def test_intent_with_special_char(self): response, content_data = self.request( self.owner_token, { - 'repository': str(self.repository.uuid), - 'text': 'my name is user', - 'intent': 'nam$s', - 'entities': [], - }) - self.assertEqual( - response.status_code, - status.HTTP_400_BAD_REQUEST) - self.assertEqual( - len(content_data.get('intent')), - 1) + "repository": str(self.repository.uuid), + "text": "my name is user", + "intent": "nam$s", + "entities": [], + }, + ) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + self.assertEqual(len(content_data.get("intent")), 1) class RetrieveRepositoryTestCase(TestCase): def setUp(self): self.factory = RequestFactory() - self.owner, self.owner_token = create_user_and_token('owner') + self.owner, self.owner_token = create_user_and_token("owner") self.user, self.user_token = create_user_and_token() self.repository = Repository.objects.create( owner=self.owner, - name='Testing', - slug='test', - language=languages.LANGUAGE_EN) + name="Testing", + slug="test", + language=languages.LANGUAGE_EN, + ) self.private_repository = Repository.objects.create( owner=self.owner, - name='Testing Private', - slug='private', + name="Testing Private", + slug="private", language=languages.LANGUAGE_EN, - is_private=True) + is_private=True, + ) def request(self, repository, token): - authorization_header = { - 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), - } + authorization_header = {"HTTP_AUTHORIZATION": "Token {}".format(token.key)} request = self.factory.get( - '/v2/repository/repository-info/{}/'.format( - str(repository.uuid)), - **authorization_header) - response = RepositoryViewSet.as_view( - {'get': 'retrieve'})( - request, - uuid=repository.uuid) + "/v2/repository/repository-info/{}/".format(str(repository.uuid)), + **authorization_header, + ) + response = RepositoryViewSet.as_view({"get": "retrieve"})( + request, uuid=repository.uuid + ) response.render() content_data = json.loads(response.content) - return (response, content_data,) + return (response, content_data) def test_allowed_in_public(self): # owner - response, content_data = self.request( - self.repository, - self.owner_token) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) + response, content_data = self.request(self.repository, self.owner_token) + self.assertEqual(response.status_code, status.HTTP_200_OK) # secondary user - response, content_data = self.request( - self.repository, - self.user_token) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) + response, content_data = self.request(self.repository, self.user_token) + self.assertEqual(response.status_code, status.HTTP_200_OK) def test_allowed_in_private(self): # owner - response, content_data = self.request( - self.private_repository, - self.owner_token) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) + response, content_data = self.request(self.private_repository, self.owner_token) + self.assertEqual(response.status_code, status.HTTP_200_OK) def test_forbidden_in_private(self): # secondary user - response, content_data = self.request( - self.private_repository, - self.user_token) - self.assertEqual( - response.status_code, - status.HTTP_403_FORBIDDEN) + response, content_data = self.request(self.private_repository, self.user_token) + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) def test_languages_status(self): authorization_header = { - 'HTTP_AUTHORIZATION': 'Token {}'.format(self.user_token.key), + "HTTP_AUTHORIZATION": "Token {}".format(self.user_token.key) } request = self.factory.get( - '/v2/repository/repository-info/{}/languagesstatus/'.format( - self.repository.uuid), - **authorization_header) - response = RepositoryViewSet.as_view( - {'get': 'languagesstatus'})( - request, - uuid=self.repository.uuid) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) + "/v2/repository/repository-info/{}/languagesstatus/".format( + self.repository.uuid + ), + **authorization_header, + ) + response = RepositoryViewSet.as_view({"get": "languagesstatus"})( + request, uuid=self.repository.uuid + ) + self.assertEqual(response.status_code, status.HTTP_200_OK) def test_available_request_authorization(self): - response, content_data = self.request( - self.repository, - self.user_token) - self.assertTrue(content_data.get('available_request_authorization')) + response, content_data = self.request(self.repository, self.user_token) + self.assertTrue(content_data.get("available_request_authorization")) def test_owner_not_available_request_authorization(self): - response, content_data = self.request( - self.repository, - self.owner_token) - self.assertFalse(content_data.get('available_request_authorization')) + response, content_data = self.request(self.repository, self.owner_token) + self.assertFalse(content_data.get("available_request_authorization")) def test_user_not_available_request_authorization(self): authorization = self.repository.get_user_authorization(self.user) authorization.role = RepositoryAuthorization.ROLE_USER authorization.save() - response, content_data = self.request( - self.repository, - self.user_token) - self.assertFalse(content_data.get('available_request_authorization')) + response, content_data = self.request(self.repository, self.user_token) + self.assertFalse(content_data.get("available_request_authorization")) def test_requested_not_available_request_authorization(self): RequestRepositoryAuthorization.objects.create( - user=self.user, - repository=self.repository, - text='I can contribute') - response, content_data = self.request( - self.repository, - self.user_token) - self.assertFalse(content_data.get('available_request_authorization')) + user=self.user, repository=self.repository, text="I can contribute" + ) + response, content_data = self.request(self.repository, self.user_token) + self.assertFalse(content_data.get("available_request_authorization")) def test_none_request_authorization(self): - response, content_data = self.request( - self.repository, - self.user_token) - self.assertIsNone(content_data.get('request_authorization')) + response, content_data = self.request(self.repository, self.user_token) + self.assertIsNone(content_data.get("request_authorization")) def test_request_authorization(self): - text = 'I can contribute' + text = "I can contribute" request = RequestRepositoryAuthorization.objects.create( - user=self.user, - repository=self.repository, - text=text) - response, content_data = self.request( - self.repository, - self.user_token) - request_authorization = content_data.get('request_authorization') - self.assertEqual( - request_authorization.get('id'), - request.id) - self.assertEqual( - request_authorization.get('text'), - text) + user=self.user, repository=self.repository, text=text + ) + response, content_data = self.request(self.repository, self.user_token) + request_authorization = content_data.get("request_authorization") + self.assertEqual(request_authorization.get("id"), request.id) + self.assertEqual(request_authorization.get("text"), text) class TrainRepositoryTestCase(TestCase): def setUp(self): self.factory = RequestFactory() - self.owner, self.owner_token = create_user_and_token('owner') + self.owner, self.owner_token = create_user_and_token("owner") self.user, self.user_token = create_user_and_token() self.repository = Repository.objects.create( owner=self.owner, - name='Testing', - slug='test', - language=languages.LANGUAGE_EN) + name="Testing", + slug="test", + language=languages.LANGUAGE_EN, + ) def request(self, repository, token): - authorization_header = { - 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), - } + authorization_header = {"HTTP_AUTHORIZATION": "Token {}".format(token.key)} request = self.factory.get( - '/v2/repository/repository-info/{}/train/'.format( - str(repository.uuid)), - **authorization_header) - response = RepositoryViewSet.as_view({'get': 'train'})(request) + "/v2/repository/repository-info/{}/train/".format(str(repository.uuid)), + **authorization_header, + ) + response = RepositoryViewSet.as_view({"get": "train"})(request) response.render() content_data = json.loads(response.content) - return (response, content_data,) + return (response, content_data) def test_permission_denied(self): response, content_data = self.request(self.repository, self.user_token) - self.assertEqual( - response.status_code, - status.HTTP_403_FORBIDDEN) + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) class AnalyzeRepositoryTestCase(TestCase): def setUp(self): self.factory = RequestFactory() - self.owner, self.owner_token = create_user_and_token('owner') + self.owner, self.owner_token = create_user_and_token("owner") self.user, self.user_token = create_user_and_token() self.repository = Repository.objects.create( owner=self.owner, - name='Testing', - slug='test', - language=languages.LANGUAGE_EN) + name="Testing", + slug="test", + language=languages.LANGUAGE_EN, + ) self.private_repository = Repository.objects.create( owner=self.owner, - name='Testing', - slug='private', + name="Testing", + slug="private", language=languages.LANGUAGE_EN, - is_private=True) + is_private=True, + ) def request(self, repository, token, data): - authorization_header = { - 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), - } + authorization_header = {"HTTP_AUTHORIZATION": "Token {}".format(token.key)} request = self.factory.post( - '/v2/repository/repository-info/{}/analyze/'.format( - str(repository.uuid)), + "/v2/repository/repository-info/{}/analyze/".format(str(repository.uuid)), data, - **authorization_header) - response = RepositoryViewSet.as_view({'post': 'analyze'})( - request, - uuid=repository.uuid) + **authorization_header, + ) + response = RepositoryViewSet.as_view({"post": "analyze"})( + request, uuid=repository.uuid + ) response.render() content_data = json.loads(response.content) - return (response, content_data,) + return (response, content_data) def test_permission_denied_in_private_repository(self): response, content_data = self.request( self.private_repository, self.user_token, - { - 'language': 'en', - 'text': 'My name is Douglas', - }) - self.assertEqual( - response.status_code, - status.HTTP_403_FORBIDDEN) + {"language": "en", "text": "My name is Douglas"}, + ) + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) def test_language_required(self): response, content_data = self.request( self.repository, self.owner_token, - { - 'language': '', - 'text': 'My name is Douglas', - }) - self.assertEqual( - response.status_code, - status.HTTP_400_BAD_REQUEST) - self.assertIn('language', content_data.keys()) + {"language": "", "text": "My name is Douglas"}, + ) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + self.assertIn("language", content_data.keys()) def test_text_required(self): response, content_data = self.request( - self.repository, - self.owner_token, - { - 'language': 'en', - 'text': '', - }) - self.assertEqual( - response.status_code, - status.HTTP_400_BAD_REQUEST) - self.assertIn('text', content_data.keys()) + self.repository, self.owner_token, {"language": "en", "text": ""} + ) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + self.assertIn("text", content_data.keys()) class UpdatesTestCase(TestCase): def setUp(self): self.factory = RequestFactory() - self.owner, self.owner_token = create_user_and_token('owner') + self.owner, self.owner_token = create_user_and_token("owner") self.repository = Repository.objects.create( owner=self.owner, - name='Testing', - slug='test', - language=languages.LANGUAGE_EN) + name="Testing", + slug="test", + language=languages.LANGUAGE_EN, + ) current_update = self.repository.current_update() RepositoryExample.objects.create( - repository_update=current_update, - text='my name is Douglas', - intent='greet') + repository_update=current_update, text="my name is Douglas", intent="greet" + ) RepositoryExample.objects.create( - repository_update=current_update, - text='my name is John', - intent='greet') + repository_update=current_update, text="my name is John", intent="greet" + ) current_update.start_training(self.owner) def request(self, data, token=None): - authorization_header = { - 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), - } if token else {} + authorization_header = ( + {"HTTP_AUTHORIZATION": "Token {}".format(token.key)} if token else {} + ) request = self.factory.get( - '/v2/repository/updates/', - data, - **authorization_header) - response = RepositoryUpdatesViewSet.as_view( - {'get': 'list'})(request) + "/v2/repository/updates/", data, **authorization_header + ) + response = RepositoryUpdatesViewSet.as_view({"get": "list"})(request) response.render() content_data = json.loads(response.content) - return (response, content_data,) + return (response, content_data) def test_okay(self): response, content_data = self.request( - { - 'repository_uuid': str(self.repository.uuid), - }, - self.owner_token) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) - self.assertEqual( - content_data.get('count'), - 1) + {"repository_uuid": str(self.repository.uuid)}, self.owner_token + ) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(content_data.get("count"), 1) def test_not_authenticated(self): response, content_data = self.request( - { - 'repository_uuid': str(self.repository.uuid), - }) - self.assertEqual( - response.status_code, - status.HTTP_401_UNAUTHORIZED) + {"repository_uuid": str(self.repository.uuid)} + ) + self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED) def test_without_repository(self): - response, content_data = self.request( - {}, - self.owner_token) - self.assertEqual( - response.status_code, - status.HTTP_400_BAD_REQUEST) + response, content_data = self.request({}, self.owner_token) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) diff --git a/bothub/api/v2/tests/test_translation.py b/bothub/api/v2/tests/test_translation.py index 8e280806..9867c274 100644 --- a/bothub/api/v2/tests/test_translation.py +++ b/bothub/api/v2/tests/test_translation.py @@ -10,8 +10,7 @@ from bothub.common.models import RepositoryExample from bothub.common.models import RepositoryTranslatedExample -from bothub.api.v2.translation.views import \ - RepositoryTranslatedExampleViewSet +from bothub.api.v2.translation.views import RepositoryTranslatedExampleViewSet from .utils import create_user_and_token @@ -20,476 +19,373 @@ class TranslateExampleTestCase(TestCase): def setUp(self): self.factory = RequestFactory() - self.owner, self.owner_token = create_user_and_token('owner') + self.owner, self.owner_token = create_user_and_token("owner") self.repository = Repository.objects.create( owner=self.owner, - name='Testing', - slug='test', - language=languages.LANGUAGE_EN) + name="Testing", + slug="test", + language=languages.LANGUAGE_EN, + ) self.example = RepositoryExample.objects.create( - repository_update=self.repository.current_update(), - text='hi') + repository_update=self.repository.current_update(), text="hi" + ) def request(self, data, user_token): - authorization_header = { - 'HTTP_AUTHORIZATION': 'Token {}'.format(user_token.key), - } + authorization_header = {"HTTP_AUTHORIZATION": "Token {}".format(user_token.key)} request = self.factory.post( - '/v2/translation/', + "/v2/translation/", json.dumps(data), - content_type='application/json', - **authorization_header) - response = RepositoryTranslatedExampleViewSet.as_view( - {'post': 'create'})(request) + content_type="application/json", + **authorization_header + ) + response = RepositoryTranslatedExampleViewSet.as_view({"post": "create"})( + request + ) response.render() content_data = json.loads(response.content) - return (response, content_data,) + return (response, content_data) def test_okay(self): response, content_data = self.request( { - 'original_example': self.example.id, - 'language': languages.LANGUAGE_PT, - 'text': 'oi', - 'entities': [], + "original_example": self.example.id, + "language": languages.LANGUAGE_PT, + "text": "oi", + "entities": [], }, - self.owner_token) - self.assertEqual( - response.status_code, - status.HTTP_201_CREATED) + self.owner_token, + ) + self.assertEqual(response.status_code, status.HTTP_201_CREATED) def test_unique_translate(self): language = languages.LANGUAGE_PT - text = 'oi' + text = "oi" RepositoryTranslatedExample.objects.create( - original_example=self.example, - language=language, - text=text) + original_example=self.example, language=language, text=text + ) response, content_data = self.request( { - 'original_example': self.example.id, - 'language': language, - 'text': text, - 'entities': [], + "original_example": self.example.id, + "language": language, + "text": text, + "entities": [], }, - self.owner_token) - self.assertEqual( - response.status_code, - status.HTTP_400_BAD_REQUEST) - self.assertIn( - 'non_field_errors', - content_data.keys()) + self.owner_token, + ) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + self.assertIn("non_field_errors", content_data.keys()) def test_forbidden(self): user, user_token = create_user_and_token() response, content_data = self.request( { - 'original_example': self.example.id, - 'language': languages.LANGUAGE_PT, - 'text': 'oi', - 'entities': [], + "original_example": self.example.id, + "language": languages.LANGUAGE_PT, + "text": "oi", + "entities": [], }, - user_token) - self.assertEqual( - response.status_code, - status.HTTP_403_FORBIDDEN) + user_token, + ) + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) def test_okay_with_entities(self): example = RepositoryExample.objects.create( - repository_update=self.repository.current_update(), - text='my name is user') + repository_update=self.repository.current_update(), text="my name is user" + ) RepositoryExampleEntity.objects.create( - repository_example=example, - start=11, - end=18, - entity='name') + repository_example=example, start=11, end=18, entity="name" + ) response, content_data = self.request( { - 'original_example': example.id, - 'language': languages.LANGUAGE_PT, - 'text': 'meu nome é user', - 'entities': [ - { - 'start': 11, - 'end': 18, - 'entity': 'name', - }, - ], + "original_example": example.id, + "language": languages.LANGUAGE_PT, + "text": "meu nome é user", + "entities": [{"start": 11, "end": 18, "entity": "name"}], }, - self.owner_token) - self.assertEqual( - response.status_code, - status.HTTP_201_CREATED) - self.assertEqual( - len(content_data.get('entities')), - 1) + self.owner_token, + ) + self.assertEqual(response.status_code, status.HTTP_201_CREATED) + self.assertEqual(len(content_data.get("entities")), 1) def test_entities_no_valid(self): example = RepositoryExample.objects.create( - repository_update=self.repository.current_update(), - text='my name is user') + repository_update=self.repository.current_update(), text="my name is user" + ) RepositoryExampleEntity.objects.create( - repository_example=self.example, - start=11, - end=18, - entity='name') + repository_example=self.example, start=11, end=18, entity="name" + ) response, content_data = self.request( { - 'original_example': example.id, - 'language': languages.LANGUAGE_PT, - 'text': 'meu nome é user', - 'entities': [ - { - 'start': 11, - 'end': 18, - 'entity': 'nome', - }, - ], + "original_example": example.id, + "language": languages.LANGUAGE_PT, + "text": "meu nome é user", + "entities": [{"start": 11, "end": 18, "entity": "nome"}], }, - self.owner_token) - self.assertEqual( - response.status_code, - status.HTTP_400_BAD_REQUEST) - self.assertEqual( - len(content_data.get('entities')), - 1) + self.owner_token, + ) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + self.assertEqual(len(content_data.get("entities")), 1) def test_entities_no_valid_2(self): example = RepositoryExample.objects.create( - repository_update=self.repository.current_update(), - text='my name is user') + repository_update=self.repository.current_update(), text="my name is user" + ) RepositoryExampleEntity.objects.create( - repository_example=self.example, - start=11, - end=18, - entity='name') + repository_example=self.example, start=11, end=18, entity="name" + ) response, content_data = self.request( { - 'original_example': example.id, - 'language': languages.LANGUAGE_PT, - 'text': 'meu nome é user', - 'entities': [ - { - 'start': 11, - 'end': 18, - 'entity': 'name', - }, - { - 'start': 0, - 'end': 3, - 'entity': 'my', - }, + "original_example": example.id, + "language": languages.LANGUAGE_PT, + "text": "meu nome é user", + "entities": [ + {"start": 11, "end": 18, "entity": "name"}, + {"start": 0, "end": 3, "entity": "my"}, ], }, - self.owner_token) - self.assertEqual( - response.status_code, - status.HTTP_400_BAD_REQUEST) - self.assertEqual( - len(content_data.get('entities')), - 1) + self.owner_token, + ) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + self.assertEqual(len(content_data.get("entities")), 1) def test_can_not_translate_to_same_language(self): response, content_data = self.request( { - 'original_example': self.example.id, - 'language': self.example.repository_update.language, - 'text': 'oi', - 'entities': [], + "original_example": self.example.id, + "language": self.example.repository_update.language, + "text": "oi", + "entities": [], }, - self.owner_token) - self.assertEqual( - response.status_code, - status.HTTP_400_BAD_REQUEST) - self.assertIn( - 'language', - content_data.keys()) + self.owner_token, + ) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + self.assertIn("language", content_data.keys()) class RepositoryTranslatedExampleRetrieveTestCase(TestCase): def setUp(self): self.factory = RequestFactory() - self.owner, self.owner_token = create_user_and_token('owner') + self.owner, self.owner_token = create_user_and_token("owner") self.repository = Repository.objects.create( owner=self.owner, - name='Testing', - slug='test', - language=languages.LANGUAGE_EN) + name="Testing", + slug="test", + language=languages.LANGUAGE_EN, + ) self.example = RepositoryExample.objects.create( - repository_update=self.repository.current_update(), - text='hi') + repository_update=self.repository.current_update(), text="hi" + ) self.translated = RepositoryTranslatedExample.objects.create( - original_example=self.example, - language=languages.LANGUAGE_PT, - text='oi') + original_example=self.example, language=languages.LANGUAGE_PT, text="oi" + ) self.private_repository = Repository.objects.create( owner=self.owner, - name='Private', - slug='private', + name="Private", + slug="private", language=languages.LANGUAGE_EN, - is_private=True) + is_private=True, + ) self.private_example = RepositoryExample.objects.create( - repository_update=self.private_repository.current_update(), - text='hi') + repository_update=self.private_repository.current_update(), text="hi" + ) self.private_translated = RepositoryTranslatedExample.objects.create( original_example=self.private_example, language=languages.LANGUAGE_PT, - text='oi') + text="oi", + ) def request(self, translated, token): - authorization_header = { - 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), - } + authorization_header = {"HTTP_AUTHORIZATION": "Token {}".format(token.key)} request = self.factory.get( - '/v2/translation/{}/'.format(translated.id), - **authorization_header) - response = RepositoryTranslatedExampleViewSet.as_view( - {'get': 'retrieve'})(request, pk=translated.id) + "/v2/translation/{}/".format(translated.id), **authorization_header + ) + response = RepositoryTranslatedExampleViewSet.as_view({"get": "retrieve"})( + request, pk=translated.id + ) response.render() content_data = json.loads(response.content) - return (response, content_data,) + return (response, content_data) def test_okay(self): - response, content_data = self.request( - self.translated, - self.owner_token) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) - self.assertEqual( - content_data.get('id'), - self.translated.id) + response, content_data = self.request(self.translated, self.owner_token) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(content_data.get("id"), self.translated.id) def test_private_okay(self): - response, content_data = self.request( - self.private_translated, - self.owner_token) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) - self.assertEqual( - content_data.get('id'), - self.private_translated.id) + response, content_data = self.request(self.private_translated, self.owner_token) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(content_data.get("id"), self.private_translated.id) def test_forbidden(self): user, user_token = create_user_and_token() - response, content_data = self.request( - self.private_translated, - user_token) - self.assertEqual( - response.status_code, - status.HTTP_403_FORBIDDEN) + response, content_data = self.request(self.private_translated, user_token) + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) class RepositoryTranslatedExampleDestroyTestCase(TestCase): def setUp(self): self.factory = RequestFactory() - self.owner, self.owner_token = create_user_and_token('owner') + self.owner, self.owner_token = create_user_and_token("owner") self.repository = Repository.objects.create( owner=self.owner, - name='Testing', - slug='test', - language=languages.LANGUAGE_EN) + name="Testing", + slug="test", + language=languages.LANGUAGE_EN, + ) self.example = RepositoryExample.objects.create( - repository_update=self.repository.current_update(), - text='hi') + repository_update=self.repository.current_update(), text="hi" + ) self.translated = RepositoryTranslatedExample.objects.create( - original_example=self.example, - language=languages.LANGUAGE_PT, - text='oi') + original_example=self.example, language=languages.LANGUAGE_PT, text="oi" + ) def request(self, translated, token): - authorization_header = { - 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), - } + authorization_header = {"HTTP_AUTHORIZATION": "Token {}".format(token.key)} request = self.factory.delete( - '/v2/translation/{}/'.format(translated.id), - **authorization_header) - response = RepositoryTranslatedExampleViewSet.as_view( - {'delete': 'destroy'})(request, pk=translated.id) + "/v2/translation/{}/".format(translated.id), **authorization_header + ) + response = RepositoryTranslatedExampleViewSet.as_view({"delete": "destroy"})( + request, pk=translated.id + ) return response def test_okay(self): - response = self.request( - self.translated, - self.owner_token) - self.assertEqual( - response.status_code, - status.HTTP_204_NO_CONTENT) + response = self.request(self.translated, self.owner_token) + self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) def test_forbidden(self): user, user_token = create_user_and_token() - response = self.request( - self.translated, - user_token) - self.assertEqual( - response.status_code, - status.HTTP_403_FORBIDDEN) + response = self.request(self.translated, user_token) + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) class TranslationsViewTest(TestCase): def setUp(self): self.factory = RequestFactory() - self.owner, self.owner_token = create_user_and_token('owner') + self.owner, self.owner_token = create_user_and_token("owner") self.repository = Repository.objects.create( owner=self.owner, - name='Testing', - slug='test', - language=languages.LANGUAGE_EN) + name="Testing", + slug="test", + language=languages.LANGUAGE_EN, + ) self.example = RepositoryExample.objects.create( - repository_update=self.repository.current_update(), - text='hi') + repository_update=self.repository.current_update(), text="hi" + ) self.translated = RepositoryTranslatedExample.objects.create( - original_example=self.example, - language=languages.LANGUAGE_PT, - text='oi') + original_example=self.example, language=languages.LANGUAGE_PT, text="oi" + ) def request(self, data, user_token=None): - authorization_header = { - 'HTTP_AUTHORIZATION': 'Token {}'.format(user_token.key), - } if user_token else {} - request = self.factory.get( - '/v2/translation/', - data, - **authorization_header) - response = RepositoryTranslatedExampleViewSet.as_view( - {'get': 'list'} - )(request) + authorization_header = ( + {"HTTP_AUTHORIZATION": "Token {}".format(user_token.key)} + if user_token + else {} + ) + request = self.factory.get("/v2/translation/", data, **authorization_header) + response = RepositoryTranslatedExampleViewSet.as_view({"get": "list"})(request) response.render() content_data = json.loads(response.content) - return (response, content_data,) + return (response, content_data) def test_okay(self): - response, content_data = self.request({ - 'repository_uuid': self.repository.uuid, - }) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) - self.assertEqual( - content_data.get('count'), - 1) + response, content_data = self.request({"repository_uuid": self.repository.uuid}) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(content_data.get("count"), 1) def test_repository_not_found(self): - response, content_data = self.request({ - 'repository_uuid': uuid.uuid4(), - }) - self.assertEqual( - response.status_code, - status.HTTP_404_NOT_FOUND) + response, content_data = self.request({"repository_uuid": uuid.uuid4()}) + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) def test_repository_uuid_invalid(self): - response, content_data = self.request({ - 'repository_uuid': 'invalid', - }) - self.assertEqual( - response.status_code, - status.HTTP_404_NOT_FOUND) + response, content_data = self.request({"repository_uuid": "invalid"}) + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) def test_forbidden(self): private_repository = Repository.objects.create( owner=self.owner, - name='Testing', - slug='private', + name="Testing", + slug="private", language=languages.LANGUAGE_EN, - is_private=True) + is_private=True, + ) - response, content_data = self.request({ - 'repository_uuid': private_repository.uuid, - }) - self.assertEqual( - response.status_code, - status.HTTP_403_FORBIDDEN) + response, content_data = self.request( + {"repository_uuid": private_repository.uuid} + ) + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) - user, user_token = create_user_and_token('user') + user, user_token = create_user_and_token("user") response, content_data = self.request( - { - 'repository_uuid': private_repository.uuid, - }, - user_token) - self.assertEqual( - response.status_code, - status.HTTP_403_FORBIDDEN) + {"repository_uuid": private_repository.uuid}, user_token + ) + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) def test_filter_from_language(self): example = RepositoryExample.objects.create( - repository_update=self.repository.current_update( - languages.LANGUAGE_ES), - text='hola') + repository_update=self.repository.current_update(languages.LANGUAGE_ES), + text="hola", + ) translated = RepositoryTranslatedExample.objects.create( - original_example=example, - language=languages.LANGUAGE_PT, - text='oi') - - response, content_data = self.request({ - 'repository_uuid': self.repository.uuid, - 'from_language': self.example.repository_update.language, - }) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) - self.assertEqual( - content_data.get('count'), - 1) - self.assertEqual( - content_data.get('results')[0].get('id'), - self.translated.id) - - response, content_data = self.request({ - 'repository_uuid': self.repository.uuid, - 'from_language': example.repository_update.language, - }) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) - self.assertEqual( - content_data.get('count'), - 1) - self.assertEqual( - content_data.get('results')[0].get('id'), - translated.id) + original_example=example, language=languages.LANGUAGE_PT, text="oi" + ) + + response, content_data = self.request( + { + "repository_uuid": self.repository.uuid, + "from_language": self.example.repository_update.language, + } + ) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(content_data.get("count"), 1) + self.assertEqual(content_data.get("results")[0].get("id"), self.translated.id) + + response, content_data = self.request( + { + "repository_uuid": self.repository.uuid, + "from_language": example.repository_update.language, + } + ) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(content_data.get("count"), 1) + self.assertEqual(content_data.get("results")[0].get("id"), translated.id) def test_filter_to_language(self): example = RepositoryExample.objects.create( - repository_update=self.repository.current_update( - languages.LANGUAGE_ES), - text='hola') + repository_update=self.repository.current_update(languages.LANGUAGE_ES), + text="hola", + ) RepositoryTranslatedExample.objects.create( - original_example=example, - language=languages.LANGUAGE_PT, - text='oi') - - response, content_data = self.request({ - 'repository_uuid': self.repository.uuid, - 'to_language': self.translated.language, - }) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) - self.assertEqual( - content_data.get('count'), - 2) - - response, content_data = self.request({ - 'repository_uuid': self.repository.uuid, - 'to_language': languages.LANGUAGE_DE, - }) - self.assertEqual( - response.status_code, - status.HTTP_200_OK) - self.assertEqual( - content_data.get('count'), - 0) + original_example=example, language=languages.LANGUAGE_PT, text="oi" + ) + + response, content_data = self.request( + { + "repository_uuid": self.repository.uuid, + "to_language": self.translated.language, + } + ) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(content_data.get("count"), 2) + + response, content_data = self.request( + { + "repository_uuid": self.repository.uuid, + "to_language": languages.LANGUAGE_DE, + } + ) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(content_data.get("count"), 0) diff --git a/bothub/api/v2/tests/utils.py b/bothub/api/v2/tests/utils.py index 7fb5780b..7ede7eb6 100644 --- a/bothub/api/v2/tests/utils.py +++ b/bothub/api/v2/tests/utils.py @@ -3,9 +3,7 @@ from bothub.authentication.models import User -def create_user_and_token(nickname='fake'): - user = User.objects.create_user( - '{}@user.com'.format(nickname), - nickname) +def create_user_and_token(nickname="fake"): + user = User.objects.create_user("{}@user.com".format(nickname), nickname) token, create = Token.objects.get_or_create(user=user) - return (user, token,) + return (user, token) diff --git a/bothub/api/v2/translation/filters.py b/bothub/api/v2/translation/filters.py index 05beb81e..ea992785 100644 --- a/bothub/api/v2/translation/filters.py +++ b/bothub/api/v2/translation/filters.py @@ -14,18 +14,21 @@ class Meta: fields = [] repository_uuid = filters.CharFilter( - field_name='repository_uuid', - method='filter_repository_uuid', + field_name="repository_uuid", + method="filter_repository_uuid", required=True, - help_text=_('Repository\'s UUID')) + help_text=_("Repository's UUID"), + ) from_language = filters.CharFilter( - field_name='language', - method='filter_from_language', - help_text='Filter by original language') + field_name="language", + method="filter_from_language", + help_text="Filter by original language", + ) to_language = filters.CharFilter( - field_name='language', - method='filter_to_language', - help_text='Filter by translated language') + field_name="language", + method="filter_to_language", + help_text="Filter by translated language", + ) def filter_repository_uuid(self, queryset, name, value): request = self.request @@ -35,16 +38,15 @@ def filter_repository_uuid(self, queryset, name, value): if not authorization.can_read: raise PermissionDenied() return RepositoryTranslatedExample.objects.filter( - original_example__repository_update__repository=repository) + original_example__repository_update__repository=repository + ) except Repository.DoesNotExist: - raise NotFound( - _('Repository {} does not exist').format(value)) + raise NotFound(_("Repository {} does not exist").format(value)) except DjangoValidationError: - raise NotFound(_('Invalid repository_uuid')) + raise NotFound(_("Invalid repository_uuid")) def filter_from_language(self, queryset, name, value): - return queryset.filter( - original_example__repository_update__language=value) + return queryset.filter(original_example__repository_update__language=value) def filter_to_language(self, queryset, name, value): return queryset.filter(language=value) diff --git a/bothub/api/v2/translation/serializers.py b/bothub/api/v2/translation/serializers.py index 0ff6cc7b..8f5999b3 100644 --- a/bothub/api/v2/translation/serializers.py +++ b/bothub/api/v2/translation/serializers.py @@ -7,44 +7,43 @@ from bothub.common.models import RepositoryTranslatedExample from bothub.common.models import RepositoryExample from bothub.common.models import RepositoryTranslatedExampleEntity -from bothub.api.v2.translation.validators import \ - CanContributeInRepositoryExampleValidator -from bothub.api.v2.translation.validators import \ - CanContributeInRepositoryTranslatedExampleValidator -from bothub.api.v2.translation.validators import \ - TranslatedExampleEntitiesValidator -from bothub.api.v2.translation.validators import \ - TranslatedExampleLanguageValidator +from bothub.api.v2.translation.validators import ( + CanContributeInRepositoryExampleValidator, +) +from bothub.api.v2.translation.validators import ( + CanContributeInRepositoryTranslatedExampleValidator, +) +from bothub.api.v2.translation.validators import TranslatedExampleEntitiesValidator +from bothub.api.v2.translation.validators import TranslatedExampleLanguageValidator class RepositoryTranslatedExampleEntitySeralizer(serializers.ModelSerializer): class Meta: model = RepositoryTranslatedExampleEntity fields = [ - 'id', - 'repository_translated_example', - 'start', - 'end', - 'entity', - 'created_at', - 'value', + "id", + "repository_translated_example", + "start", + "end", + "entity", + "created_at", + "value", ] ref_name = None repository_translated_example = serializers.PrimaryKeyRelatedField( queryset=RepositoryTranslatedExample.objects, - validators=[ - CanContributeInRepositoryTranslatedExampleValidator(), - ], - help_text='Example translation ID', - required=False) + validators=[CanContributeInRepositoryTranslatedExampleValidator()], + help_text="Example translation ID", + required=False, + ) entity = serializers.SerializerMethodField(required=False) value = serializers.SerializerMethodField(required=False) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - if kwargs.get('data') == 'POST': - self.fields['entity'] = EntityValueField() + if kwargs.get("data") == "POST": + self.fields["entity"] = EntityValueField() def get_entity(self, obj): return obj.entity.value @@ -57,43 +56,37 @@ class RepositoryTranslatedExampleSerializer(serializers.ModelSerializer): class Meta: model = RepositoryTranslatedExample fields = [ - 'id', - 'original_example', - 'from_language', - 'language', - 'text', - 'has_valid_entities', - 'entities', - 'created_at', + "id", + "original_example", + "from_language", + "language", + "text", + "has_valid_entities", + "entities", + "created_at", ] ref_name = None def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - if kwargs['context'].get('request').stream: - self.fields['entities'] = \ - RepositoryTranslatedExampleEntitySeralizer( - many=True, - style={'text_field': 'text'}, - data='POST' - ) + if kwargs["context"].get("request").stream: + self.fields["entities"] = RepositoryTranslatedExampleEntitySeralizer( + many=True, style={"text_field": "text"}, data="POST" + ) self.validators.append(TranslatedExampleEntitiesValidator()) self.validators.append(TranslatedExampleLanguageValidator()) original_example = serializers.PrimaryKeyRelatedField( queryset=RepositoryExample.objects, - validators=[ - CanContributeInRepositoryExampleValidator(), - ], - help_text=_('Example\'s ID')) + validators=[CanContributeInRepositoryExampleValidator()], + help_text=_("Example's ID"), + ) from_language = serializers.SerializerMethodField(required=False) - language = serializers.ChoiceField( - LANGUAGE_CHOICES, - label=_('Language')) + language = serializers.ChoiceField(LANGUAGE_CHOICES, label=_("Language")) has_valid_entities = serializers.SerializerMethodField() entities = RepositoryTranslatedExampleEntitySeralizer( - many=True, - style={'text_field': 'text'}) + many=True, style={"text_field": "text"} + ) def get_from_language(self, obj): return obj.original_example.repository_update.language @@ -102,11 +95,11 @@ def get_has_valid_entities(self, obj): return obj.has_valid_entities def create(self, validated_data): - entities_data = validated_data.pop('entities') + entities_data = validated_data.pop("entities") translated = self.Meta.model.objects.create(**validated_data) for entity_data in entities_data: RepositoryTranslatedExampleEntity.objects.create( - repository_translated_example=translated, - **entity_data) + repository_translated_example=translated, **entity_data + ) return translated diff --git a/bothub/api/v2/translation/validators.py b/bothub/api/v2/translation/validators.py index 6c52550f..b7844fb3 100644 --- a/bothub/api/v2/translation/validators.py +++ b/bothub/api/v2/translation/validators.py @@ -8,56 +8,58 @@ class CanContributeInRepositoryExampleValidator(object): def __call__(self, value): repository = value.repository_update.repository - user_authorization = repository.get_user_authorization( - self.request.user) + user_authorization = repository.get_user_authorization(self.request.user) if not user_authorization.can_contribute: - raise PermissionDenied( - _('You can\'t contribute in this repository')) + raise PermissionDenied(_("You can't contribute in this repository")) def set_context(self, serializer): - self.request = serializer.context.get('request') + self.request = serializer.context.get("request") class CanContributeInRepositoryTranslatedExampleValidator(object): def __call__(self, value): repository = value.original_example.repository_update.repository - user_authorization = repository.get_user_authorization( - self.request.user) + user_authorization = repository.get_user_authorization(self.request.user) if not user_authorization.can_contribute: - raise PermissionDenied( - _('You can\'t contribute in this repository')) + raise PermissionDenied(_("You can't contribute in this repository")) def set_context(self, serializer): - self.request = serializer.context.get('request') + self.request = serializer.context.get("request") class TranslatedExampleEntitiesValidator(object): def __call__(self, attrs): - original_example = attrs.get('original_example') - entities_list = list(map(lambda x: dict(x), attrs.get('entities'))) - original_entities_list = list(map( - lambda x: x.to_dict, - original_example.entities.all())) + original_example = attrs.get("original_example") + entities_list = list(map(lambda x: dict(x), attrs.get("entities"))) + original_entities_list = list( + map(lambda x: x.to_dict, original_example.entities.all()) + ) entities_valid = RepositoryTranslatedExample.same_entities_validator( - entities_list, - original_entities_list) + entities_list, original_entities_list + ) if not entities_valid: - raise ValidationError({'entities': _( - 'Entities need to match from the original content. ' + - 'Entities: {0}. Original entities: {1}.').format( - RepositoryTranslatedExample.count_entities( - entities_list, - to_str=True), - RepositoryTranslatedExample.count_entities( - original_entities_list, - to_str=True), - )}) + raise ValidationError( + { + "entities": _( + "Entities need to match from the original content. " + + "Entities: {0}. Original entities: {1}." + ).format( + RepositoryTranslatedExample.count_entities( + entities_list, to_str=True + ), + RepositoryTranslatedExample.count_entities( + original_entities_list, to_str=True + ), + ) + } + ) class TranslatedExampleLanguageValidator(object): def __call__(self, attrs): - original_example = attrs.get('original_example') - language = attrs.get('language') + original_example = attrs.get("original_example") + language = attrs.get("language") if original_example.repository_update.language == language: - raise ValidationError({'language': _( - 'Can\'t translate to the same language')}) + raise ValidationError( + {"language": _("Can't translate to the same language")} + ) diff --git a/bothub/api/v2/translation/views.py b/bothub/api/v2/translation/views.py index 1bb77517..0743db50 100644 --- a/bothub/api/v2/translation/views.py +++ b/bothub/api/v2/translation/views.py @@ -3,20 +3,19 @@ from rest_framework import permissions from bothub.common.models import RepositoryTranslatedExample -from bothub.api.v2.translation.permissions import \ - RepositoryTranslatedExamplePermission -from bothub.api.v2.translation.serializers import \ - RepositoryTranslatedExampleSerializer +from bothub.api.v2.translation.permissions import RepositoryTranslatedExamplePermission +from bothub.api.v2.translation.serializers import RepositoryTranslatedExampleSerializer from bothub.api.v2.translation.filters import TranslationsFilter class RepositoryTranslatedExampleViewSet( - mixins.CreateModelMixin, - mixins.ListModelMixin, - mixins.RetrieveModelMixin, - mixins.UpdateModelMixin, - mixins.DestroyModelMixin, - GenericViewSet): + mixins.CreateModelMixin, + mixins.ListModelMixin, + mixins.RetrieveModelMixin, + mixins.UpdateModelMixin, + mixins.DestroyModelMixin, + GenericViewSet, +): """ Manager example translation. @@ -35,6 +34,7 @@ class RepositoryTranslatedExampleViewSet( delete: Delete example translation. """ + queryset = RepositoryTranslatedExample.objects serializer_class = RepositoryTranslatedExampleSerializer permission_classes = [ diff --git a/bothub/api/v2/urls.py b/bothub/api/v2/urls.py index 8a8d5ad6..55728b65 100644 --- a/bothub/api/v2/urls.py +++ b/bothub/api/v2/urls.py @@ -6,8 +6,9 @@ urlpatterns = [ path( - 'repository-shortcut///', + "repository-shortcut///", views.repository_shortcut, - name='repository-shortcut'), - path('', include(router.urls)), + name="repository-shortcut", + ), + path("", include(router.urls)), ] diff --git a/bothub/api/v2/views.py b/bothub/api/v2/views.py index f757a426..c8936e87 100644 --- a/bothub/api/v2/views.py +++ b/bothub/api/v2/views.py @@ -6,4 +6,4 @@ def repository_shortcut(self, **kwargs): # pragma: no cover repository = get_object_or_404(Repository, **kwargs) - return redirect('repository-detail', uuid=repository.uuid) + return redirect("repository-detail", uuid=repository.uuid) diff --git a/bothub/authentication/apps.py b/bothub/authentication/apps.py index 9635c9df..372ba813 100644 --- a/bothub/authentication/apps.py +++ b/bothub/authentication/apps.py @@ -2,4 +2,4 @@ class AuthenticationConfig(AppConfig): - name = 'authentication' + name = "authentication" diff --git a/bothub/authentication/migrations/0001_initial.py b/bothub/authentication/migrations/0001_initial.py index c7a4e595..ec4270a2 100644 --- a/bothub/authentication/migrations/0001_initial.py +++ b/bothub/authentication/migrations/0001_initial.py @@ -9,31 +9,90 @@ class Migration(migrations.Migration): initial = True - dependencies = [ - ('auth', '0009_alter_user_last_name_max_length'), - ] + dependencies = [("auth", "0009_alter_user_last_name_max_length")] operations = [ migrations.CreateModel( - name='User', + name="User", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('password', models.CharField(max_length=128, verbose_name='password')), - ('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')), - ('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')), - ('email', models.EmailField(max_length=254, unique=True, verbose_name='email')), - ('name', models.CharField(max_length=32, verbose_name='name')), - ('nick', models.CharField(max_length=16, validators=[django.core.validators.RegexValidator(re.compile('^[-a-zA-Z0-9_]+\\Z'), "Enter a valid 'nick' consisting of letters, numbers, underscores or hyphens.", 'invalid')], verbose_name='nick')), - ('locale', models.CharField(max_length=48, verbose_name='locale')), - ('is_staff', models.BooleanField(default=False, verbose_name='staff status')), - ('is_active', models.BooleanField(default=True, verbose_name='active')), - ('joined_at', models.DateField(auto_now_add=True, verbose_name='joined at')), - ('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.Group', verbose_name='groups')), - ('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.Permission', verbose_name='user permissions')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("password", models.CharField(max_length=128, verbose_name="password")), + ( + "last_login", + models.DateTimeField( + blank=True, null=True, verbose_name="last login" + ), + ), + ( + "is_superuser", + models.BooleanField( + default=False, + help_text="Designates that this user has all permissions without explicitly assigning them.", + verbose_name="superuser status", + ), + ), + ( + "email", + models.EmailField( + max_length=254, unique=True, verbose_name="email" + ), + ), + ("name", models.CharField(max_length=32, verbose_name="name")), + ( + "nick", + models.CharField( + max_length=16, + validators=[ + django.core.validators.RegexValidator( + re.compile("^[-a-zA-Z0-9_]+\\Z"), + "Enter a valid 'nick' consisting of letters, numbers, underscores or hyphens.", + "invalid", + ) + ], + verbose_name="nick", + ), + ), + ("locale", models.CharField(max_length=48, verbose_name="locale")), + ( + "is_staff", + models.BooleanField(default=False, verbose_name="staff status"), + ), + ("is_active", models.BooleanField(default=True, verbose_name="active")), + ( + "joined_at", + models.DateField(auto_now_add=True, verbose_name="joined at"), + ), + ( + "groups", + models.ManyToManyField( + blank=True, + help_text="The groups this user belongs to. A user will get all permissions granted to each of their groups.", + related_name="user_set", + related_query_name="user", + to="auth.Group", + verbose_name="groups", + ), + ), + ( + "user_permissions", + models.ManyToManyField( + blank=True, + help_text="Specific permissions for this user.", + related_name="user_set", + related_query_name="user", + to="auth.Permission", + verbose_name="user permissions", + ), + ), ], - options={ - 'verbose_name': 'user', - 'verbose_name_plural': 'users', - }, - ), + options={"verbose_name": "user", "verbose_name_plural": "users"}, + ) ] diff --git a/bothub/authentication/migrations/0002_auto_20180315_1343.py b/bothub/authentication/migrations/0002_auto_20180315_1343.py index 90d3e3f9..e3dc6e2a 100644 --- a/bothub/authentication/migrations/0002_auto_20180315_1343.py +++ b/bothub/authentication/migrations/0002_auto_20180315_1343.py @@ -7,34 +7,48 @@ class Migration(migrations.Migration): - dependencies = [ - ('authentication', '0001_initial'), - ] + dependencies = [("authentication", "0001_initial")] operations = [ - migrations.RenameField( - model_name='user', - old_name='nick', - new_name='nickname', - ), + migrations.RenameField(model_name="user", old_name="nick", new_name="nickname"), migrations.AlterField( - model_name='user', - name='nickname', - field=models.CharField(help_text="User's nickname, using letters, numbers, underscores and hyphens without spaces.", max_length=16, validators=[django.core.validators.RegexValidator(re.compile('^[-a-zA-Z0-9_]+\\Z'), "Enter a valid 'nickname' consisting of letters, numbers, underscores or hyphens.", 'invalid')], verbose_name='nickname'), + model_name="user", + name="nickname", + field=models.CharField( + help_text="User's nickname, using letters, numbers, underscores and hyphens without spaces.", + max_length=16, + validators=[ + django.core.validators.RegexValidator( + re.compile("^[-a-zA-Z0-9_]+\\Z"), + "Enter a valid 'nickname' consisting of letters, numbers, underscores or hyphens.", + "invalid", + ) + ], + verbose_name="nickname", + ), ), migrations.AlterField( - model_name='user', - name='email', - field=models.EmailField(help_text="User's email.", max_length=254, unique=True, verbose_name='email'), + model_name="user", + name="email", + field=models.EmailField( + help_text="User's email.", + max_length=254, + unique=True, + verbose_name="email", + ), ), migrations.AlterField( - model_name='user', - name='locale', - field=models.CharField(help_text="User's locale.", max_length=48, verbose_name='locale'), + model_name="user", + name="locale", + field=models.CharField( + help_text="User's locale.", max_length=48, verbose_name="locale" + ), ), migrations.AlterField( - model_name='user', - name='name', - field=models.CharField(help_text="User's name.", max_length=32, verbose_name='name'), + model_name="user", + name="name", + field=models.CharField( + help_text="User's name.", max_length=32, verbose_name="name" + ), ), ] diff --git a/bothub/authentication/migrations/0003_auto_20180522_1705.py b/bothub/authentication/migrations/0003_auto_20180522_1705.py index f2c16439..ed544d92 100644 --- a/bothub/authentication/migrations/0003_auto_20180522_1705.py +++ b/bothub/authentication/migrations/0003_auto_20180522_1705.py @@ -5,14 +5,17 @@ class Migration(migrations.Migration): - dependencies = [ - ('authentication', '0002_auto_20180315_1343'), - ] + dependencies = [("authentication", "0002_auto_20180315_1343")] operations = [ migrations.AlterField( - model_name='user', - name='locale', - field=models.CharField(blank=True, help_text="User's locale.", max_length=48, verbose_name='locale'), - ), + model_name="user", + name="locale", + field=models.CharField( + blank=True, + help_text="User's locale.", + max_length=48, + verbose_name="locale", + ), + ) ] diff --git a/bothub/authentication/migrations/0004_auto_20180605_1357.py b/bothub/authentication/migrations/0004_auto_20180605_1357.py index b1f0de42..89df1c54 100644 --- a/bothub/authentication/migrations/0004_auto_20180605_1357.py +++ b/bothub/authentication/migrations/0004_auto_20180605_1357.py @@ -7,14 +7,24 @@ class Migration(migrations.Migration): - dependencies = [ - ('authentication', '0003_auto_20180522_1705'), - ] + dependencies = [("authentication", "0003_auto_20180522_1705")] operations = [ migrations.AlterField( - model_name='user', - name='nickname', - field=models.CharField(help_text="User's nickname, using letters, numbers, underscores and hyphens without spaces.", max_length=16, unique=True, validators=[django.core.validators.RegexValidator(re.compile('^[-a-zA-Z0-9_]+\\Z'), "Enter a valid 'nickname' consisting of letters, numbers, underscores or hyphens.", 'invalid')], verbose_name='nickname'), - ), + model_name="user", + name="nickname", + field=models.CharField( + help_text="User's nickname, using letters, numbers, underscores and hyphens without spaces.", + max_length=16, + unique=True, + validators=[ + django.core.validators.RegexValidator( + re.compile("^[-a-zA-Z0-9_]+\\Z"), + "Enter a valid 'nickname' consisting of letters, numbers, underscores or hyphens.", + "invalid", + ) + ], + verbose_name="nickname", + ), + ) ] diff --git a/bothub/authentication/migrations/0005_auto_20180620_2059.py b/bothub/authentication/migrations/0005_auto_20180620_2059.py index efb7d95f..784fa963 100644 --- a/bothub/authentication/migrations/0005_auto_20180620_2059.py +++ b/bothub/authentication/migrations/0005_auto_20180620_2059.py @@ -8,14 +8,25 @@ class Migration(migrations.Migration): - dependencies = [ - ('authentication', '0004_auto_20180605_1357'), - ] + dependencies = [("authentication", "0004_auto_20180605_1357")] operations = [ migrations.AlterField( - model_name='user', - name='nickname', - field=models.CharField(help_text="User's nickname, using letters, numbers, underscores and hyphens without spaces.", max_length=16, unique=True, validators=[django.core.validators.RegexValidator(re.compile('^[-a-zA-Z0-9_]+\\Z'), "Enter a valid 'nickname' consisting of letters, numbers, underscores or hyphens.", 'invalid'), bothub.authentication.models.validate_user_nickname_value], verbose_name='nickname'), - ), + model_name="user", + name="nickname", + field=models.CharField( + help_text="User's nickname, using letters, numbers, underscores and hyphens without spaces.", + max_length=16, + unique=True, + validators=[ + django.core.validators.RegexValidator( + re.compile("^[-a-zA-Z0-9_]+\\Z"), + "Enter a valid 'nickname' consisting of letters, numbers, underscores or hyphens.", + "invalid", + ), + bothub.authentication.models.validate_user_nickname_value, + ], + verbose_name="nickname", + ), + ) ] diff --git a/bothub/authentication/models.py b/bothub/authentication/models.py index ab2de30a..ef8b9221 100644 --- a/bothub/authentication/models.py +++ b/bothub/authentication/models.py @@ -12,27 +12,28 @@ from django.dispatch import receiver -user_nickname_re = _lazy_re_compile(r'^[-a-zA-Z0-9_]+\Z') +user_nickname_re = _lazy_re_compile(r"^[-a-zA-Z0-9_]+\Z") validate_user_nickname_format = RegexValidator( user_nickname_re, - _('Enter a valid \'nickname\' consisting of letters, numbers, ' + - 'underscores or hyphens.'), - 'invalid' + _( + "Enter a valid 'nickname' consisting of letters, numbers, " + + "underscores or hyphens." + ), + "invalid", ) def validate_user_nickname_value(value): - if value in ['api', 'docs', 'admin', 'ping', 'static']: - raise ValidationError( - _('The user nickname can\'t be \'{}\'').format(value)) + if value in ["api", "docs", "admin", "ping", "static"]: + raise ValidationError(_("The user nickname can't be '{}'").format(value)) class UserManager(BaseUserManager): def _create_user(self, email, nickname, password=None, **extra_fields): if not email: - raise ValueError('The given email must be set') + raise ValueError("The given email must be set") if not nickname: - raise ValueError('The given nick must be set') + raise ValueError("The given nick must be set") email = self.normalize_email(email) user = self.model(email=email, nickname=nickname, **extra_fields) @@ -41,60 +42,46 @@ def _create_user(self, email, nickname, password=None, **extra_fields): return user def create_user(self, email, nickname, password=None, **extra_fields): - extra_fields.setdefault('is_superuser', False) + extra_fields.setdefault("is_superuser", False) return self._create_user(email, nickname, password, **extra_fields) def create_superuser(self, email, nickname, password=None, **extra_fields): - extra_fields.setdefault('is_superuser', True) - extra_fields.setdefault('is_staff', True) + extra_fields.setdefault("is_superuser", True) + extra_fields.setdefault("is_staff", True) - if extra_fields.get('is_superuser') is not True: - raise ValueError('Superuser must have is_superuser=True.') + if extra_fields.get("is_superuser") is not True: + raise ValueError("Superuser must have is_superuser=True.") return self._create_user(email, nickname, password, **extra_fields) class User(AbstractBaseUser, PermissionsMixin): class Meta: - verbose_name = _('user') - verbose_name_plural = _('users') + verbose_name = _("user") + verbose_name_plural = _("users") - USERNAME_FIELD = 'email' - REQUIRED_FIELDS = ['nickname'] + USERNAME_FIELD = "email" + REQUIRED_FIELDS = ["nickname"] - email = models.EmailField( - _('email'), - unique=True, - help_text=_('User\'s email.')) - name = models.CharField( - _('name'), - max_length=32, - help_text=_('User\'s name.')) + email = models.EmailField(_("email"), unique=True, help_text=_("User's email.")) + name = models.CharField(_("name"), max_length=32, help_text=_("User's name.")) nickname = models.CharField( - _('nickname'), + _("nickname"), max_length=16, - validators=[ - validate_user_nickname_format, - validate_user_nickname_value, - ], - help_text=_('User\'s nickname, using letters, numbers, underscores ' + - 'and hyphens without spaces.'), - unique=True) + validators=[validate_user_nickname_format, validate_user_nickname_value], + help_text=_( + "User's nickname, using letters, numbers, underscores " + + "and hyphens without spaces." + ), + unique=True, + ) locale = models.CharField( - _('locale'), - max_length=48, - help_text=_('User\'s locale.'), - blank=True) - is_staff = models.BooleanField( - _('staff status'), - default=False) - is_active = models.BooleanField( - _('active'), - default=True) - joined_at = models.DateField( - _('joined at'), - auto_now_add=True) + _("locale"), max_length=48, help_text=_("User's locale."), blank=True + ) + is_staff = models.BooleanField(_("staff status"), default=False) + is_active = models.BooleanField(_("active"), default=True) + joined_at = models.DateField(_("joined at"), auto_now_add=True) objects = UserManager() @@ -105,19 +92,16 @@ def token_generator(self): def send_welcome_email(self): if not settings.SEND_EMAILS: return False # pragma: no cover - context = { - 'name': self.name, - } + context = {"name": self.name} send_mail( - _('Welcome to Bothub'), - render_to_string( - 'authentication/emails/welcome.txt', - context), + _("Welcome to Bothub"), + render_to_string("authentication/emails/welcome.txt", context), None, [self.email], html_message=render_to_string( - 'authentication/emails/welcome.html', - context)) + "authentication/emails/welcome.html", context + ), + ) def make_password_reset_token(self): return self.token_generator.make_token(self) @@ -126,23 +110,19 @@ def send_reset_password_email(self): if not settings.SEND_EMAILS: return False # pragma: no cover token = self.make_password_reset_token() - reset_url = '{}reset-password/{}/{}/'.format( - settings.BOTHUB_WEBAPP_BASE_URL, - self.nickname, - token) - context = { - 'reset_url': reset_url, - } + reset_url = "{}reset-password/{}/{}/".format( + settings.BOTHUB_WEBAPP_BASE_URL, self.nickname, token + ) + context = {"reset_url": reset_url} send_mail( - _('Reset your bothub password'), - render_to_string( - 'authentication/emails/reset_password.txt', - context), + _("Reset your bothub password"), + render_to_string("authentication/emails/reset_password.txt", context), None, [self.email], html_message=render_to_string( - 'authentication/emails/reset_password.html', - context),) + "authentication/emails/reset_password.html", context + ), + ) def check_password_reset_token(self, token): return self.token_generator.check_token(self, token) diff --git a/bothub/authentication/tests.py b/bothub/authentication/tests.py index 4de51088..7fb92ed4 100644 --- a/bothub/authentication/tests.py +++ b/bothub/authentication/tests.py @@ -6,27 +6,24 @@ class AuthenticationTestCase(TestCase): def test_new_user(self): - User.objects.create_user('fake@user.com', 'fake') + User.objects.create_user("fake@user.com", "fake") def test_new_superuser(self): - User.objects.create_superuser('fake@user.com', 'fake') + User.objects.create_superuser("fake@user.com", "fake") def test_new_user_fail_without_email(self): with self.assertRaises(ValueError): - User.objects._create_user('', 'fake') + User.objects._create_user("", "fake") def test_new_user_fail_without_nickname(self): with self.assertRaises(ValueError): - User.objects._create_user('fake@user.com', '') + User.objects._create_user("fake@user.com", "") def test_new_superuser_fail_issuperuser_false(self): with self.assertRaises(ValueError): - User.objects.create_superuser( - 'fake@user.com', - 'fake', - is_superuser=False) + User.objects.create_superuser("fake@user.com", "fake", is_superuser=False) def test_user_unique_nickname(self): - User.objects.create_user('user1@user.com', 'fake') + User.objects.create_user("user1@user.com", "fake") with self.assertRaises(IntegrityError): - User.objects.create_user('user2@user.com', 'fake') + User.objects.create_user("user2@user.com", "fake") diff --git a/bothub/common/admin.py b/bothub/common/admin.py index 03091a1b..69b71d0c 100644 --- a/bothub/common/admin.py +++ b/bothub/common/admin.py @@ -13,57 +13,40 @@ class RepositoryUpdateInline(admin.TabularInline): can_delete = False fields = [ - 'language', - 'algorithm', - 'use_competing_intents', - 'use_name_entities', - 'created_at', - 'by', - 'training_started_at', - 'trained_at', - 'failed_at', - 'training_log', - 'download_bot_data', + "language", + "algorithm", + "use_competing_intents", + "use_name_entities", + "created_at", + "by", + "training_started_at", + "trained_at", + "failed_at", + "training_log", + "download_bot_data", ] readonly_fields = fields def download_bot_data(self, obj): # pragma: no cover if not obj.trained_at: - return '-' - return format_html(""" + return "-" + return format_html( + """ Download Bot Data -""".format(reverse('download_bot_data', kwargs={'update_id': obj.id}))) +""".format( + reverse("download_bot_data", kwargs={"update_id": obj.id}) + ) + ) @admin.register(Repository) class RepositoryAdmin(admin.ModelAdmin): - list_display = [ - '__str__', - 'uuid', - 'language', - 'is_private', - 'created_at', - ] - search_fields = [ - 'name', - 'uuid', - 'language', - 'owner__nickname', - 'slug', - ] - list_filter = [ - 'is_private', - 'language', - 'categories', - ] - inlines = [ - RepositoryUpdateInline, - ] + list_display = ["__str__", "uuid", "language", "is_private", "created_at"] + search_fields = ["name", "uuid", "language", "owner__nickname", "slug"] + list_filter = ["is_private", "language", "categories"] + inlines = [RepositoryUpdateInline] @admin.register(RepositoryCategory) class RepositoryCategoryAdmin(admin.ModelAdmin): - list_display = [ - '__str__', - 'icon', - ] + list_display = ["__str__", "icon"] diff --git a/bothub/common/apps.py b/bothub/common/apps.py index 5f2f0784..3ce38941 100644 --- a/bothub/common/apps.py +++ b/bothub/common/apps.py @@ -2,4 +2,4 @@ class CommonConfig(AppConfig): - name = 'common' + name = "common" diff --git a/bothub/common/languages.py b/bothub/common/languages.py index 087b02bd..1647c18d 100644 --- a/bothub/common/languages.py +++ b/bothub/common/languages.py @@ -3,89 +3,88 @@ from django.core.exceptions import ValidationError -LANGUAGE_EN = 'en' -LANGUAGE_DE = 'de' -LANGUAGE_ES = 'es' -LANGUAGE_PT = 'pt' -LANGUAGE_FR = 'fr' -LANGUAGE_IT = 'it' -LANGUAGE_NL = 'nl' -LANGUAGE_PT_BR = 'pt_br' -LANGUAGE_ID = 'id' -LANGUAGE_MN = 'mn' -LANGUAGE_AR = 'ar' -LANGUAGE_BN = 'bn' -LANGUAGE_HI = 'hi' -LANGUAGE_RU = 'ru' -LANGUAGE_TH = 'th' -LANGUAGE_VI = 'vi' -LANGUAGE_KH = 'kh' -LANGUAGE_SW = 'sw' -LANGUAGE_CA = 'ca' -LANGUAGE_DA = 'da' -LANGUAGE_EL = 'el' -LANGUAGE_FA = 'fa' -LANGUAGE_FI = 'fi' -LANGUAGE_GA = 'ga' -LANGUAGE_HE = 'he' -LANGUAGE_HR = 'hr' -LANGUAGE_HU = 'hu' -LANGUAGE_JA = 'ja' -LANGUAGE_NB = 'nb' -LANGUAGE_PL = 'pl' -LANGUAGE_RO = 'ro' -LANGUAGE_SI = 'si' -LANGUAGE_SV = 'sv' -LANGUAGE_TE = 'te' -LANGUAGE_TR = 'tr' -LANGUAGE_TT = 'tt' -LANGUAGE_UR = 'ur' -LANGUAGE_ZH = 'zh' +LANGUAGE_EN = "en" +LANGUAGE_DE = "de" +LANGUAGE_ES = "es" +LANGUAGE_PT = "pt" +LANGUAGE_FR = "fr" +LANGUAGE_IT = "it" +LANGUAGE_NL = "nl" +LANGUAGE_PT_BR = "pt_br" +LANGUAGE_ID = "id" +LANGUAGE_MN = "mn" +LANGUAGE_AR = "ar" +LANGUAGE_BN = "bn" +LANGUAGE_HI = "hi" +LANGUAGE_RU = "ru" +LANGUAGE_TH = "th" +LANGUAGE_VI = "vi" +LANGUAGE_KH = "kh" +LANGUAGE_SW = "sw" +LANGUAGE_CA = "ca" +LANGUAGE_DA = "da" +LANGUAGE_EL = "el" +LANGUAGE_FA = "fa" +LANGUAGE_FI = "fi" +LANGUAGE_GA = "ga" +LANGUAGE_HE = "he" +LANGUAGE_HR = "hr" +LANGUAGE_HU = "hu" +LANGUAGE_JA = "ja" +LANGUAGE_NB = "nb" +LANGUAGE_PL = "pl" +LANGUAGE_RO = "ro" +LANGUAGE_SI = "si" +LANGUAGE_SV = "sv" +LANGUAGE_TE = "te" +LANGUAGE_TR = "tr" +LANGUAGE_TT = "tt" +LANGUAGE_UR = "ur" +LANGUAGE_ZH = "zh" VERBOSE_LANGUAGES = { - LANGUAGE_EN: _('English'), - LANGUAGE_DE: _('German'), - LANGUAGE_ES: _('Spanish'), - LANGUAGE_PT: _('Portuguese'), - LANGUAGE_FR: _('French'), - LANGUAGE_IT: _('Italian'), - LANGUAGE_NL: _('Dutch'), - LANGUAGE_PT_BR: _('Brazilian Portuguese'), - LANGUAGE_ID: _('Indonesian'), - LANGUAGE_MN: _('Mongolian'), - LANGUAGE_AR: _('Arabic'), - LANGUAGE_BN: _('Bengali'), - LANGUAGE_HI: _('Hindi'), - LANGUAGE_RU: _('Russian'), - LANGUAGE_TH: _('Thai'), - LANGUAGE_VI: _('Vietnamese'), - LANGUAGE_KH: _('Khmer'), - LANGUAGE_SW: _('Swahili'), - LANGUAGE_CA: _('Catalan'), - LANGUAGE_DA: _('Danish'), - LANGUAGE_EL: _('Greek'), - LANGUAGE_FA: _('Persian'), - LANGUAGE_FI: _('Finnish'), - LANGUAGE_GA: _('Irish'), - LANGUAGE_HE: _('Hebrew'), - LANGUAGE_HR: _('Croatian'), - LANGUAGE_HU: _('Hungarian'), - LANGUAGE_JA: _('Japanese'), - LANGUAGE_NB: _('Norwegian'), - LANGUAGE_PL: _('Polish'), - LANGUAGE_RO: _('Romanian'), - LANGUAGE_SI: _('Sinhala'), - LANGUAGE_SV: _('Swedish'), - LANGUAGE_TE: _('Telugu'), - LANGUAGE_TR: _('Turkish'), - LANGUAGE_TT: _('Tatar'), - LANGUAGE_UR: _('Urdu'), - LANGUAGE_ZH: _('Chinese'), + LANGUAGE_EN: _("English"), + LANGUAGE_DE: _("German"), + LANGUAGE_ES: _("Spanish"), + LANGUAGE_PT: _("Portuguese"), + LANGUAGE_FR: _("French"), + LANGUAGE_IT: _("Italian"), + LANGUAGE_NL: _("Dutch"), + LANGUAGE_PT_BR: _("Brazilian Portuguese"), + LANGUAGE_ID: _("Indonesian"), + LANGUAGE_MN: _("Mongolian"), + LANGUAGE_AR: _("Arabic"), + LANGUAGE_BN: _("Bengali"), + LANGUAGE_HI: _("Hindi"), + LANGUAGE_RU: _("Russian"), + LANGUAGE_TH: _("Thai"), + LANGUAGE_VI: _("Vietnamese"), + LANGUAGE_KH: _("Khmer"), + LANGUAGE_SW: _("Swahili"), + LANGUAGE_CA: _("Catalan"), + LANGUAGE_DA: _("Danish"), + LANGUAGE_EL: _("Greek"), + LANGUAGE_FA: _("Persian"), + LANGUAGE_FI: _("Finnish"), + LANGUAGE_GA: _("Irish"), + LANGUAGE_HE: _("Hebrew"), + LANGUAGE_HR: _("Croatian"), + LANGUAGE_HU: _("Hungarian"), + LANGUAGE_JA: _("Japanese"), + LANGUAGE_NB: _("Norwegian"), + LANGUAGE_PL: _("Polish"), + LANGUAGE_RO: _("Romanian"), + LANGUAGE_SI: _("Sinhala"), + LANGUAGE_SV: _("Swedish"), + LANGUAGE_TE: _("Telugu"), + LANGUAGE_TR: _("Turkish"), + LANGUAGE_TT: _("Tatar"), + LANGUAGE_UR: _("Urdu"), + LANGUAGE_ZH: _("Chinese"), } LANGUAGE_CHOICES = [ - (l, VERBOSE_LANGUAGES.get(l, l)) for l in - settings.SUPPORTED_LANGUAGES + (l, VERBOSE_LANGUAGES.get(l, l)) for l in settings.SUPPORTED_LANGUAGES ] @@ -95,5 +94,4 @@ def is_valid_language(value): # pragma: no cover def validate_language(value): # pragma: no cover if not is_valid_language(value): - raise ValidationError(_( - '{} is not a supported language.').format(value)) + raise ValidationError(_("{} is not a supported language.").format(value)) diff --git a/bothub/common/management/commands/fill_db_using_fake_data.py b/bothub/common/management/commands/fill_db_using_fake_data.py index 19f26875..f44c8644 100644 --- a/bothub/common/management/commands/fill_db_using_fake_data.py +++ b/bothub/common/management/commands/fill_db_using_fake_data.py @@ -23,118 +23,114 @@ class Command(BaseCommand): def handle(self, *args, **kwargs): - assert settings.DEBUG, 'Don\'t run this command in production' + assert settings.DEBUG, "Don't run this command in production" # Users User.objects.create_superuser( - email='admin@bothub.it', - nickname='admin', - password='admin', - name='Admin') + email="admin@bothub.it", nickname="admin", password="admin", name="Admin" + ) user = User.objects.create_user( - email='user@bothub.it', - nickname='user', - password='user', - name='User') + email="user@bothub.it", nickname="user", password="user", name="User" + ) # Categories - categories = list(map( - lambda x: RepositoryCategory.objects.create( - name='Category {}'.format(x)), - range(1, 6))) + categories = list( + map( + lambda x: RepositoryCategory.objects.create( + name="Category {}".format(x) + ), + range(1, 6), + ) + ) # Repositories repository_1 = Repository.objects.create( owner=user, - name='Repository 1', - slug='repo1', - language=languages.LANGUAGE_EN) + name="Repository 1", + slug="repo1", + language=languages.LANGUAGE_EN, + ) repository_1.categories.add(categories[0]) repository_1.categories.add(categories[1]) repository_1.categories.add(categories[3]) repository_2 = Repository.objects.create( owner=user, - name='Repository 2', - slug='repo2', - language=languages.LANGUAGE_EN) + name="Repository 2", + slug="repo2", + language=languages.LANGUAGE_EN, + ) repository_2.categories.add(categories[0]) repository_2.categories.add(categories[2]) for x in range(3, 46): new_repository = Repository.objects.create( owner=user, - name='Repository {}'.format(x), - slug='repo{}'.format(x), - language=languages.LANGUAGE_EN) + name="Repository {}".format(x), + slug="repo{}".format(x), + language=languages.LANGUAGE_EN, + ) new_repository.categories.add(random.choice(categories)) # Examples example_1 = RepositoryExample.objects.create( - repository_update=repository_1.current_update(), - text='hi', - intent='greet') + repository_update=repository_1.current_update(), text="hi", intent="greet" + ) example_2 = RepositoryExample.objects.create( repository_update=repository_1.current_update(), - text='hello', - intent='greet') + text="hello", + intent="greet", + ) example_3 = RepositoryExample.objects.create( - repository_update=repository_1.current_update(), - text='yes', - intent='affirm') + repository_update=repository_1.current_update(), text="yes", intent="affirm" + ) RepositoryExample.objects.create( - repository_update=repository_1.current_update(), - text='yep', - intent='affirm') + repository_update=repository_1.current_update(), text="yep", intent="affirm" + ) example_5 = RepositoryExample.objects.create( repository_update=repository_1.current_update(), - text='show me chinese restaurants', - intent='restaurant_search') + text="show me chinese restaurants", + intent="restaurant_search", + ) # Example Entity RepositoryExampleEntity.objects.create( - repository_example=example_1, - start=8, - end=15, - entity='cuisine') + repository_example=example_1, start=8, end=15, entity="cuisine" + ) RepositoryExampleEntity.objects.create( - repository_example=example_5, - start=8, - end=15, - entity='cuisine') + repository_example=example_5, start=8, end=15, entity="cuisine" + ) # Translated Example RepositoryTranslatedExample.objects.create( - original_example=example_1, - language=languages.LANGUAGE_PT, - text='oi') + original_example=example_1, language=languages.LANGUAGE_PT, text="oi" + ) RepositoryTranslatedExample.objects.create( - original_example=example_2, - language=languages.LANGUAGE_PT, - text='olá') + original_example=example_2, language=languages.LANGUAGE_PT, text="olá" + ) RepositoryTranslatedExample.objects.create( - original_example=example_3, - language=languages.LANGUAGE_PT, - text='sim') + original_example=example_3, language=languages.LANGUAGE_PT, text="sim" + ) tranlated_4 = RepositoryTranslatedExample.objects.create( original_example=example_5, language=languages.LANGUAGE_PT, - text='mostre me restaurantes chinês') + text="mostre me restaurantes chinês", + ) # Translated Example Entity @@ -142,55 +138,48 @@ def handle(self, *args, **kwargs): repository_translated_example=tranlated_4, start=23, end=29, - entity='cuisine') + entity="cuisine", + ) # Evaluates evalute_1 = RepositoryEvaluate.objects.create( repository_update=repository_1.current_update(), - text='show me chinese restaurants', - intent='restaurant_search') + text="show me chinese restaurants", + intent="restaurant_search", + ) evalute_2 = RepositoryEvaluate.objects.create( repository_update=repository_1.current_update(), - text='hello', - intent='greet') + text="hello", + intent="greet", + ) RepositoryEvaluate.objects.create( - repository_update=repository_1.current_update(), - text='yes', - intent='affirm') + repository_update=repository_1.current_update(), text="yes", intent="affirm" + ) RepositoryEvaluate.objects.create( - repository_update=repository_1.current_update(), - text='yep', - intent='affirm') + repository_update=repository_1.current_update(), text="yep", intent="affirm" + ) RepositoryEvaluateEntity.objects.create( - repository_evaluate=evalute_1, - start=23, - end=29, - entity='cuisine') + repository_evaluate=evalute_1, start=23, end=29, entity="cuisine" + ) RepositoryEvaluateEntity.objects.create( - repository_evaluate=evalute_2, - start=0, - end=5, - entity='greet') + repository_evaluate=evalute_2, start=0, end=5, entity="greet" + ) # Evaluate Report for x in range(0, 2): intent_results = RepositoryEvaluateResultScore.objects.create( - f1_score=0.976, - precision=0.978, - accuracy=0.976, + f1_score=0.976, precision=0.978, accuracy=0.976 ) entity_results = RepositoryEvaluateResultScore.objects.create( - f1_score=0.977, - precision=0.978, - accuracy=0.978, + f1_score=0.977, precision=0.978, accuracy=0.978 ) evaluate_log = [ @@ -199,123 +188,95 @@ def handle(self, *args, **kwargs): "intent": "greet", "intent_prediction": { "name": "greet", - "confidence": 0.9263743763408538 + "confidence": 0.9263743763408538, }, - "status": "success" + "status": "success", }, { "text": "howdy", "intent": "greet", "intent_prediction": { "name": "greet", - "confidence": 0.8099720606047796 + "confidence": 0.8099720606047796, }, - "status": "success" + "status": "success", }, { "text": "hey there", "intent": "greet", "intent_prediction": { "name": "greet", - "confidence": 0.8227075176309955 + "confidence": 0.8227075176309955, }, - "status": "success" + "status": "success", }, { "text": "test with nlu", "intent": "restaurant_search", "intent_prediction": { "name": "goodbye", - "confidence": 0.3875259420712092 + "confidence": 0.3875259420712092, }, - "status": "error" - } + "status": "error", + }, ] - sample_url = 'https://s3.amazonaws.com/bothub-sample' + sample_url = "https://s3.amazonaws.com/bothub-sample" evaluate_result = RepositoryEvaluateResult.objects.create( repository_update=repository_1.current_update(), intent_results=intent_results, entity_results=entity_results, - matrix_chart='{}/confmat.png'.format(sample_url), - confidence_chart='{}/hist.png'.format(sample_url), + matrix_chart="{}/confmat.png".format(sample_url), + confidence_chart="{}/hist.png".format(sample_url), log=json.dumps(evaluate_log), ) intent_score_1 = RepositoryEvaluateResultScore.objects.create( - precision=1.0, - recall=1.0, - f1_score=1.0, - support=11, + precision=1.0, recall=1.0, f1_score=1.0, support=11 ) intent_score_2 = RepositoryEvaluateResultScore.objects.create( - precision=0.89, - recall=1.0, - f1_score=0.94, - support=8, + precision=0.89, recall=1.0, f1_score=0.94, support=8 ) intent_score_3 = RepositoryEvaluateResultScore.objects.create( - precision=1.0, - recall=1.0, - f1_score=1.0, - support=8, + precision=1.0, recall=1.0, f1_score=1.0, support=8 ) intent_score_4 = RepositoryEvaluateResultScore.objects.create( - precision=1.0, - recall=0.93, - f1_score=0.97, - support=15, + precision=1.0, recall=0.93, f1_score=0.97, support=15 ) RepositoryEvaluateResultIntent.objects.create( - evaluate_result=evaluate_result, - intent='affirm', - score=intent_score_1, + evaluate_result=evaluate_result, intent="affirm", score=intent_score_1 ) RepositoryEvaluateResultIntent.objects.create( - evaluate_result=evaluate_result, - intent='goodbye', - score=intent_score_2, + evaluate_result=evaluate_result, intent="goodbye", score=intent_score_2 ) RepositoryEvaluateResultIntent.objects.create( - evaluate_result=evaluate_result, - intent='greet', - score=intent_score_3, + evaluate_result=evaluate_result, intent="greet", score=intent_score_3 ) RepositoryEvaluateResultIntent.objects.create( evaluate_result=evaluate_result, - intent='restaurant_search', + intent="restaurant_search", score=intent_score_4, ) entity_score_1 = RepositoryEvaluateResultScore.objects.create( - precision=1.0, - recall=0.90, - f1_score=0.95, - support=10, + precision=1.0, recall=0.90, f1_score=0.95, support=10 ) entity_score_2 = RepositoryEvaluateResultScore.objects.create( - precision=1.0, - recall=0.75, - f1_score=0.86, - support=8, + precision=1.0, recall=0.75, f1_score=0.86, support=8 ) RepositoryEvaluateResultEntity.objects.create( - evaluate_result=evaluate_result, - entity='cuisine', - score=entity_score_1, + evaluate_result=evaluate_result, entity="cuisine", score=entity_score_1 ) RepositoryEvaluateResultEntity.objects.create( - evaluate_result=evaluate_result, - entity='greet', - score=entity_score_2, + evaluate_result=evaluate_result, entity="greet", score=entity_score_2 ) diff --git a/bothub/common/migrations/0001_initial.py b/bothub/common/migrations/0001_initial.py index 55e0fa2a..f18ed6ac 100644 --- a/bothub/common/migrations/0001_initial.py +++ b/bothub/common/migrations/0001_initial.py @@ -10,153 +10,370 @@ class Migration(migrations.Migration): initial = True - dependencies = [ - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ] + dependencies = [migrations.swappable_dependency(settings.AUTH_USER_MODEL)] operations = [ migrations.CreateModel( - name='Repository', + name="Repository", fields=[ - ('uuid', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False, verbose_name='UUID')), - ('name', models.CharField(max_length=64, verbose_name='name')), - ('slug', models.SlugField(max_length=32, unique=True, verbose_name='slug')), - ('language', models.CharField(choices=[('en', 'English'), ('de', 'German'), ('es', 'Spanish'), ('pt', 'Portuguese'), ('fr', 'French'), ('it', 'Italian'), ('nl', 'Dutch')], max_length=2, verbose_name='language')), - ('description', models.TextField(blank=True, verbose_name='description')), - ('is_private', models.BooleanField(default=False, verbose_name='private')), - ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='created at')), + ( + "uuid", + models.UUIDField( + default=uuid.uuid4, + editable=False, + primary_key=True, + serialize=False, + verbose_name="UUID", + ), + ), + ("name", models.CharField(max_length=64, verbose_name="name")), + ( + "slug", + models.SlugField(max_length=32, unique=True, verbose_name="slug"), + ), + ( + "language", + models.CharField( + choices=[ + ("en", "English"), + ("de", "German"), + ("es", "Spanish"), + ("pt", "Portuguese"), + ("fr", "French"), + ("it", "Italian"), + ("nl", "Dutch"), + ], + max_length=2, + verbose_name="language", + ), + ), + ( + "description", + models.TextField(blank=True, verbose_name="description"), + ), + ( + "is_private", + models.BooleanField(default=False, verbose_name="private"), + ), + ( + "created_at", + models.DateTimeField(auto_now_add=True, verbose_name="created at"), + ), ], options={ - 'verbose_name': 'repository', - 'verbose_name_plural': 'repositories', + "verbose_name": "repository", + "verbose_name_plural": "repositories", }, ), migrations.CreateModel( - name='RepositoryAuthorization', + name="RepositoryAuthorization", fields=[ - ('uuid', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False, verbose_name='UUID')), - ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='created at')), - ('repository', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='common.Repository')), - ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ( + "uuid", + models.UUIDField( + default=uuid.uuid4, + editable=False, + primary_key=True, + serialize=False, + verbose_name="UUID", + ), + ), + ( + "created_at", + models.DateTimeField(auto_now_add=True, verbose_name="created at"), + ), + ( + "repository", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="common.Repository", + ), + ), + ( + "user", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to=settings.AUTH_USER_MODEL, + ), + ), ], options={ - 'verbose_name': 'repository authorization', - 'verbose_name_plural': 'repository authorizations', + "verbose_name": "repository authorization", + "verbose_name_plural": "repository authorizations", }, ), migrations.CreateModel( - name='RepositoryCategory', + name="RepositoryCategory", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', models.CharField(max_length=32, verbose_name='name')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("name", models.CharField(max_length=32, verbose_name="name")), ], options={ - 'verbose_name': 'repository category', - 'verbose_name_plural': 'repository categories', + "verbose_name": "repository category", + "verbose_name_plural": "repository categories", }, ), migrations.CreateModel( - name='RepositoryExample', + name="RepositoryExample", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('text', models.TextField(verbose_name='text')), - ('intent', models.CharField(blank=True, max_length=64, verbose_name='intent')), - ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='created at')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("text", models.TextField(verbose_name="text")), + ( + "intent", + models.CharField(blank=True, max_length=64, verbose_name="intent"), + ), + ( + "created_at", + models.DateTimeField(auto_now_add=True, verbose_name="created at"), + ), ], options={ - 'verbose_name': 'repository example', - 'verbose_name_plural': 'repository examples', + "verbose_name": "repository example", + "verbose_name_plural": "repository examples", }, ), migrations.CreateModel( - name='RepositoryExampleEntity', + name="RepositoryExampleEntity", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('start', models.PositiveIntegerField(verbose_name='start')), - ('end', models.PositiveIntegerField(verbose_name='end')), - ('entity', models.CharField(max_length=64, verbose_name='entity')), - ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='created at')), - ('repository_example', models.ForeignKey(editable=False, on_delete=django.db.models.deletion.CASCADE, related_name='entities', to='common.RepositoryExample')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("start", models.PositiveIntegerField(verbose_name="start")), + ("end", models.PositiveIntegerField(verbose_name="end")), + ("entity", models.CharField(max_length=64, verbose_name="entity")), + ( + "created_at", + models.DateTimeField(auto_now_add=True, verbose_name="created at"), + ), + ( + "repository_example", + models.ForeignKey( + editable=False, + on_delete=django.db.models.deletion.CASCADE, + related_name="entities", + to="common.RepositoryExample", + ), + ), ], options={ - 'verbose_name': 'repository example entity', - 'verbose_name_plural': 'repository example entities', - 'abstract': False, + "verbose_name": "repository example entity", + "verbose_name_plural": "repository example entities", + "abstract": False, }, ), migrations.CreateModel( - name='RepositoryTranslatedExample', + name="RepositoryTranslatedExample", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('language', models.CharField(choices=[('en', 'English'), ('de', 'German'), ('es', 'Spanish'), ('pt', 'Portuguese'), ('fr', 'French'), ('it', 'Italian'), ('nl', 'Dutch')], max_length=2, verbose_name='language')), - ('text', models.TextField(verbose_name='text')), - ('original_example', models.ForeignKey(editable=False, on_delete=django.db.models.deletion.CASCADE, related_name='translations', to='common.RepositoryExample')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "language", + models.CharField( + choices=[ + ("en", "English"), + ("de", "German"), + ("es", "Spanish"), + ("pt", "Portuguese"), + ("fr", "French"), + ("it", "Italian"), + ("nl", "Dutch"), + ], + max_length=2, + verbose_name="language", + ), + ), + ("text", models.TextField(verbose_name="text")), + ( + "original_example", + models.ForeignKey( + editable=False, + on_delete=django.db.models.deletion.CASCADE, + related_name="translations", + to="common.RepositoryExample", + ), + ), ], options={ - 'verbose_name': 'repository translated example', - 'verbose_name_plural': 'repository translated examples', + "verbose_name": "repository translated example", + "verbose_name_plural": "repository translated examples", }, ), migrations.CreateModel( - name='RepositoryTranslatedExampleEntity', + name="RepositoryTranslatedExampleEntity", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('start', models.PositiveIntegerField(verbose_name='start')), - ('end', models.PositiveIntegerField(verbose_name='end')), - ('entity', models.CharField(max_length=64, verbose_name='entity')), - ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='created at')), - ('repository_translated_example', models.ForeignKey(editable=False, on_delete=django.db.models.deletion.CASCADE, related_name='entities', to='common.RepositoryTranslatedExample')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("start", models.PositiveIntegerField(verbose_name="start")), + ("end", models.PositiveIntegerField(verbose_name="end")), + ("entity", models.CharField(max_length=64, verbose_name="entity")), + ( + "created_at", + models.DateTimeField(auto_now_add=True, verbose_name="created at"), + ), + ( + "repository_translated_example", + models.ForeignKey( + editable=False, + on_delete=django.db.models.deletion.CASCADE, + related_name="entities", + to="common.RepositoryTranslatedExample", + ), + ), ], options={ - 'verbose_name': 'repository example entity', - 'verbose_name_plural': 'repository example entities', - 'abstract': False, + "verbose_name": "repository example entity", + "verbose_name_plural": "repository example entities", + "abstract": False, }, ), migrations.CreateModel( - name='RepositoryUpdate', + name="RepositoryUpdate", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('language', models.CharField(choices=[('en', 'English'), ('de', 'German'), ('es', 'Spanish'), ('pt', 'Portuguese'), ('fr', 'French'), ('it', 'Italian'), ('nl', 'Dutch')], max_length=2, verbose_name='language')), - ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='created at')), - ('bot_data', models.TextField(blank=True, editable=False, verbose_name='bot data')), - ('training_started_at', models.DateTimeField(blank=True, null=True, verbose_name='training started at')), - ('trained_at', models.DateTimeField(blank=True, null=True, verbose_name='trained at')), - ('by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), - ('repository', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='updates', to='common.Repository')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "language", + models.CharField( + choices=[ + ("en", "English"), + ("de", "German"), + ("es", "Spanish"), + ("pt", "Portuguese"), + ("fr", "French"), + ("it", "Italian"), + ("nl", "Dutch"), + ], + max_length=2, + verbose_name="language", + ), + ), + ( + "created_at", + models.DateTimeField(auto_now_add=True, verbose_name="created at"), + ), + ( + "bot_data", + models.TextField( + blank=True, editable=False, verbose_name="bot data" + ), + ), + ( + "training_started_at", + models.DateTimeField( + blank=True, null=True, verbose_name="training started at" + ), + ), + ( + "trained_at", + models.DateTimeField( + blank=True, null=True, verbose_name="trained at" + ), + ), + ( + "by", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + to=settings.AUTH_USER_MODEL, + ), + ), + ( + "repository", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="updates", + to="common.Repository", + ), + ), ], options={ - 'verbose_name': 'repository update', - 'verbose_name_plural': 'repository updates', - 'ordering': ['-created_at'], + "verbose_name": "repository update", + "verbose_name_plural": "repository updates", + "ordering": ["-created_at"], }, ), migrations.AddField( - model_name='repositoryexample', - name='deleted_in', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='deleted', to='common.RepositoryUpdate'), + model_name="repositoryexample", + name="deleted_in", + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="deleted", + to="common.RepositoryUpdate", + ), ), migrations.AddField( - model_name='repositoryexample', - name='repository_update', - field=models.ForeignKey(editable=False, on_delete=django.db.models.deletion.CASCADE, related_name='added', to='common.RepositoryUpdate'), + model_name="repositoryexample", + name="repository_update", + field=models.ForeignKey( + editable=False, + on_delete=django.db.models.deletion.CASCADE, + related_name="added", + to="common.RepositoryUpdate", + ), ), migrations.AddField( - model_name='repository', - name='categories', - field=models.ManyToManyField(to='common.RepositoryCategory'), + model_name="repository", + name="categories", + field=models.ManyToManyField(to="common.RepositoryCategory"), ), migrations.AddField( - model_name='repository', - name='owner', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), + model_name="repository", + name="owner", + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL + ), ), migrations.AlterUniqueTogether( - name='repositorytranslatedexample', - unique_together={('original_example', 'language')}, + name="repositorytranslatedexample", + unique_together={("original_example", "language")}, ), migrations.AlterUniqueTogether( - name='repositoryauthorization', - unique_together={('user', 'repository')}, + name="repositoryauthorization", unique_together={("user", "repository")} ), ] diff --git a/bothub/common/migrations/0002_auto_20180315_1343.py b/bothub/common/migrations/0002_auto_20180315_1343.py index 190da772..4f23c9c1 100644 --- a/bothub/common/migrations/0002_auto_20180315_1343.py +++ b/bothub/common/migrations/0002_auto_20180315_1343.py @@ -6,104 +6,185 @@ class Migration(migrations.Migration): - dependencies = [ - ('common', '0001_initial'), - ] + dependencies = [("common", "0001_initial")] operations = [ migrations.AlterField( - model_name='repository', - name='categories', - field=models.ManyToManyField(help_text='Categories for approaching repositories with the same purpose', to='common.RepositoryCategory'), - ), - migrations.AlterField( - model_name='repository', - name='description', - field=models.TextField(blank=True, help_text='Tell what your bot do!', verbose_name='description'), - ), - migrations.AlterField( - model_name='repository', - name='is_private', - field=models.BooleanField(default=False, help_text='Your repository can be private, only you can see and use, or can be public and all community can see and use.', verbose_name='private'), - ), - migrations.AlterField( - model_name='repository', - name='language', - field=models.CharField(choices=[('en', 'English'), ('de', 'German'), ('es', 'Spanish'), ('pt', 'Portuguese'), ('fr', 'French'), ('it', 'Italian'), ('nl', 'Dutch')], help_text="Repository's examples language. The examples can be translated to other languages.", max_length=2, verbose_name='language'), - ), - migrations.AlterField( - model_name='repository', - name='name', - field=models.CharField(help_text='Repository display name', max_length=64, verbose_name='name'), - ), - migrations.AlterField( - model_name='repository', - name='slug', - field=models.SlugField(help_text='Easy way to found and share repositories', max_length=32, unique=True, verbose_name='slug'), - ), - migrations.AlterField( - model_name='repositoryexample', - name='intent', - field=models.CharField(blank=True, help_text='Example intent reference', max_length=64, verbose_name='intent'), - ), - migrations.AlterField( - model_name='repositoryexample', - name='text', - field=models.TextField(help_text='Example text', verbose_name='text'), - ), - migrations.AlterField( - model_name='repositoryexampleentity', - name='end', - field=models.PositiveIntegerField(help_text='End index of entity value in example text', verbose_name='end'), - ), - migrations.AlterField( - model_name='repositoryexampleentity', - name='entity', - field=models.CharField(help_text='Entity name', max_length=64, verbose_name='entity'), - ), - migrations.AlterField( - model_name='repositoryexampleentity', - name='repository_example', - field=models.ForeignKey(editable=False, help_text='Example object', on_delete=django.db.models.deletion.CASCADE, related_name='entities', to='common.RepositoryExample'), - ), - migrations.AlterField( - model_name='repositoryexampleentity', - name='start', - field=models.PositiveIntegerField(help_text='Start index of entity value in example text', verbose_name='start'), - ), - migrations.AlterField( - model_name='repositorytranslatedexample', - name='language', - field=models.CharField(choices=[('en', 'English'), ('de', 'German'), ('es', 'Spanish'), ('pt', 'Portuguese'), ('fr', 'French'), ('it', 'Italian'), ('nl', 'Dutch')], help_text='Translation language', max_length=2, verbose_name='language'), - ), - migrations.AlterField( - model_name='repositorytranslatedexample', - name='original_example', - field=models.ForeignKey(editable=False, help_text='Example object', on_delete=django.db.models.deletion.CASCADE, related_name='translations', to='common.RepositoryExample'), - ), - migrations.AlterField( - model_name='repositorytranslatedexample', - name='text', - field=models.TextField(help_text='Translation text', verbose_name='text'), - ), - migrations.AlterField( - model_name='repositorytranslatedexampleentity', - name='end', - field=models.PositiveIntegerField(help_text='End index of entity value in example text', verbose_name='end'), - ), - migrations.AlterField( - model_name='repositorytranslatedexampleentity', - name='entity', - field=models.CharField(help_text='Entity name', max_length=64, verbose_name='entity'), - ), - migrations.AlterField( - model_name='repositorytranslatedexampleentity', - name='repository_translated_example', - field=models.ForeignKey(editable=False, help_text='Translated example object', on_delete=django.db.models.deletion.CASCADE, related_name='entities', to='common.RepositoryTranslatedExample'), - ), - migrations.AlterField( - model_name='repositorytranslatedexampleentity', - name='start', - field=models.PositiveIntegerField(help_text='Start index of entity value in example text', verbose_name='start'), + model_name="repository", + name="categories", + field=models.ManyToManyField( + help_text="Categories for approaching repositories with the same purpose", + to="common.RepositoryCategory", + ), + ), + migrations.AlterField( + model_name="repository", + name="description", + field=models.TextField( + blank=True, + help_text="Tell what your bot do!", + verbose_name="description", + ), + ), + migrations.AlterField( + model_name="repository", + name="is_private", + field=models.BooleanField( + default=False, + help_text="Your repository can be private, only you can see and use, or can be public and all community can see and use.", + verbose_name="private", + ), + ), + migrations.AlterField( + model_name="repository", + name="language", + field=models.CharField( + choices=[ + ("en", "English"), + ("de", "German"), + ("es", "Spanish"), + ("pt", "Portuguese"), + ("fr", "French"), + ("it", "Italian"), + ("nl", "Dutch"), + ], + help_text="Repository's examples language. The examples can be translated to other languages.", + max_length=2, + verbose_name="language", + ), + ), + migrations.AlterField( + model_name="repository", + name="name", + field=models.CharField( + help_text="Repository display name", max_length=64, verbose_name="name" + ), + ), + migrations.AlterField( + model_name="repository", + name="slug", + field=models.SlugField( + help_text="Easy way to found and share repositories", + max_length=32, + unique=True, + verbose_name="slug", + ), + ), + migrations.AlterField( + model_name="repositoryexample", + name="intent", + field=models.CharField( + blank=True, + help_text="Example intent reference", + max_length=64, + verbose_name="intent", + ), + ), + migrations.AlterField( + model_name="repositoryexample", + name="text", + field=models.TextField(help_text="Example text", verbose_name="text"), + ), + migrations.AlterField( + model_name="repositoryexampleentity", + name="end", + field=models.PositiveIntegerField( + help_text="End index of entity value in example text", + verbose_name="end", + ), + ), + migrations.AlterField( + model_name="repositoryexampleentity", + name="entity", + field=models.CharField( + help_text="Entity name", max_length=64, verbose_name="entity" + ), + ), + migrations.AlterField( + model_name="repositoryexampleentity", + name="repository_example", + field=models.ForeignKey( + editable=False, + help_text="Example object", + on_delete=django.db.models.deletion.CASCADE, + related_name="entities", + to="common.RepositoryExample", + ), + ), + migrations.AlterField( + model_name="repositoryexampleentity", + name="start", + field=models.PositiveIntegerField( + help_text="Start index of entity value in example text", + verbose_name="start", + ), + ), + migrations.AlterField( + model_name="repositorytranslatedexample", + name="language", + field=models.CharField( + choices=[ + ("en", "English"), + ("de", "German"), + ("es", "Spanish"), + ("pt", "Portuguese"), + ("fr", "French"), + ("it", "Italian"), + ("nl", "Dutch"), + ], + help_text="Translation language", + max_length=2, + verbose_name="language", + ), + ), + migrations.AlterField( + model_name="repositorytranslatedexample", + name="original_example", + field=models.ForeignKey( + editable=False, + help_text="Example object", + on_delete=django.db.models.deletion.CASCADE, + related_name="translations", + to="common.RepositoryExample", + ), + ), + migrations.AlterField( + model_name="repositorytranslatedexample", + name="text", + field=models.TextField(help_text="Translation text", verbose_name="text"), + ), + migrations.AlterField( + model_name="repositorytranslatedexampleentity", + name="end", + field=models.PositiveIntegerField( + help_text="End index of entity value in example text", + verbose_name="end", + ), + ), + migrations.AlterField( + model_name="repositorytranslatedexampleentity", + name="entity", + field=models.CharField( + help_text="Entity name", max_length=64, verbose_name="entity" + ), + ), + migrations.AlterField( + model_name="repositorytranslatedexampleentity", + name="repository_translated_example", + field=models.ForeignKey( + editable=False, + help_text="Translated example object", + on_delete=django.db.models.deletion.CASCADE, + related_name="entities", + to="common.RepositoryTranslatedExample", + ), + ), + migrations.AlterField( + model_name="repositorytranslatedexampleentity", + name="start", + field=models.PositiveIntegerField( + help_text="Start index of entity value in example text", + verbose_name="start", + ), ), ] diff --git a/bothub/common/migrations/0003_auto_20180503_1223.py b/bothub/common/migrations/0003_auto_20180503_1223.py index 7212794f..db97f822 100644 --- a/bothub/common/migrations/0003_auto_20180503_1223.py +++ b/bothub/common/migrations/0003_auto_20180503_1223.py @@ -8,17 +8,20 @@ class Migration(migrations.Migration): dependencies = [ migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ('common', '0002_auto_20180315_1343'), + ("common", "0002_auto_20180315_1343"), ] operations = [ migrations.AlterField( - model_name='repository', - name='slug', - field=models.SlugField(help_text='Easy way to found and share repositories', max_length=32, verbose_name='slug'), + model_name="repository", + name="slug", + field=models.SlugField( + help_text="Easy way to found and share repositories", + max_length=32, + verbose_name="slug", + ), ), migrations.AlterUniqueTogether( - name='repository', - unique_together={('owner', 'slug')}, + name="repository", unique_together={("owner", "slug")} ), ] diff --git a/bothub/common/migrations/0004_auto_20180514_1129.py b/bothub/common/migrations/0004_auto_20180514_1129.py index 4fe07ba3..c22e08c8 100644 --- a/bothub/common/migrations/0004_auto_20180514_1129.py +++ b/bothub/common/migrations/0004_auto_20180514_1129.py @@ -5,13 +5,15 @@ class Migration(migrations.Migration): - dependencies = [ - ('common', '0003_auto_20180503_1223'), - ] + dependencies = [("common", "0003_auto_20180503_1223")] operations = [ migrations.AlterModelOptions( - name='repositoryexample', - options={'ordering': ['-created_at'], 'verbose_name': 'repository example', 'verbose_name_plural': 'repository examples'}, - ), + name="repositoryexample", + options={ + "ordering": ["-created_at"], + "verbose_name": "repository example", + "verbose_name_plural": "repository examples", + }, + ) ] diff --git a/bothub/common/migrations/0005_repositorytranslatedexample_repository_update.py b/bothub/common/migrations/0005_repositorytranslatedexample_repository_update.py index 3e4c0a15..6620f87a 100644 --- a/bothub/common/migrations/0005_repositorytranslatedexample_repository_update.py +++ b/bothub/common/migrations/0005_repositorytranslatedexample_repository_update.py @@ -5,27 +5,39 @@ def set_repository_update(apps, schema_editor): - RepositoryTranslatedExample = apps.get_model('common', 'RepositoryTranslatedExample') + RepositoryTranslatedExample = apps.get_model( + "common", "RepositoryTranslatedExample" + ) for translate in RepositoryTranslatedExample.objects.all().iterator(): translate.repository_update = translate.original_example.repository_update translate.save() + class Migration(migrations.Migration): - dependencies = [ - ('common', '0004_auto_20180514_1129'), - ] + dependencies = [("common", "0004_auto_20180514_1129")] operations = [ migrations.AddField( - model_name='repositorytranslatedexample', - name='repository_update', - field=models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='translated_added', to='common.RepositoryUpdate'), + model_name="repositorytranslatedexample", + name="repository_update", + field=models.ForeignKey( + editable=False, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="translated_added", + to="common.RepositoryUpdate", + ), ), migrations.RunPython(set_repository_update), migrations.AlterField( - model_name='repositorytranslatedexample', - name='repository_update', - field=models.ForeignKey(editable=False, on_delete=django.db.models.deletion.CASCADE, related_name='translated_added', to='common.RepositoryUpdate'), + model_name="repositorytranslatedexample", + name="repository_update", + field=models.ForeignKey( + editable=False, + on_delete=django.db.models.deletion.CASCADE, + related_name="translated_added", + to="common.RepositoryUpdate", + ), ), ] diff --git a/bothub/common/migrations/0006_repositoryupdate_failed_at.py b/bothub/common/migrations/0006_repositoryupdate_failed_at.py index 1e85d04c..4703b1b7 100644 --- a/bothub/common/migrations/0006_repositoryupdate_failed_at.py +++ b/bothub/common/migrations/0006_repositoryupdate_failed_at.py @@ -5,14 +5,12 @@ class Migration(migrations.Migration): - dependencies = [ - ('common', '0005_repositorytranslatedexample_repository_update'), - ] + dependencies = [("common", "0005_repositorytranslatedexample_repository_update")] operations = [ migrations.AddField( - model_name='repositoryupdate', - name='failed_at', - field=models.DateTimeField(blank=True, null=True, verbose_name='failed at'), - ), + model_name="repositoryupdate", + name="failed_at", + field=models.DateTimeField(blank=True, null=True, verbose_name="failed at"), + ) ] diff --git a/bothub/common/migrations/0007_repositorytranslatedexample_created_at.py b/bothub/common/migrations/0007_repositorytranslatedexample_created_at.py index 4d6a05d5..b1f648b3 100644 --- a/bothub/common/migrations/0007_repositorytranslatedexample_created_at.py +++ b/bothub/common/migrations/0007_repositorytranslatedexample_created_at.py @@ -6,15 +6,17 @@ class Migration(migrations.Migration): - dependencies = [ - ('common', '0006_repositoryupdate_failed_at'), - ] + dependencies = [("common", "0006_repositoryupdate_failed_at")] operations = [ migrations.AddField( - model_name='repositorytranslatedexample', - name='created_at', - field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now, verbose_name='created at'), + model_name="repositorytranslatedexample", + name="created_at", + field=models.DateTimeField( + auto_now_add=True, + default=django.utils.timezone.now, + verbose_name="created at", + ), preserve_default=False, - ), + ) ] diff --git a/bothub/common/migrations/0008_auto_20180529_1340.py b/bothub/common/migrations/0008_auto_20180529_1340.py index b857e606..bc73d02c 100644 --- a/bothub/common/migrations/0008_auto_20180529_1340.py +++ b/bothub/common/migrations/0008_auto_20180529_1340.py @@ -5,13 +5,15 @@ class Migration(migrations.Migration): - dependencies = [ - ('common', '0007_repositorytranslatedexample_created_at'), - ] + dependencies = [("common", "0007_repositorytranslatedexample_created_at")] operations = [ migrations.AlterModelOptions( - name='repositorytranslatedexample', - options={'ordering': ['-created_at'], 'verbose_name': 'repository translated example', 'verbose_name_plural': 'repository translated examples'}, - ), + name="repositorytranslatedexample", + options={ + "ordering": ["-created_at"], + "verbose_name": "repository translated example", + "verbose_name_plural": "repository translated examples", + }, + ) ] diff --git a/bothub/common/migrations/0009_auto_20180601_1348.py b/bothub/common/migrations/0009_auto_20180601_1348.py index c55a8359..df3c966c 100644 --- a/bothub/common/migrations/0009_auto_20180601_1348.py +++ b/bothub/common/migrations/0009_auto_20180601_1348.py @@ -9,25 +9,52 @@ class Migration(migrations.Migration): dependencies = [ migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ('common', '0008_auto_20180529_1340'), + ("common", "0008_auto_20180529_1340"), ] operations = [ migrations.CreateModel( - name='RepositoryVote', + name="RepositoryVote", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('vote', models.IntegerField(choices=[(1, 'Up'), (-1, 'Down'), (0, 'Neutral')], verbose_name='vote')), - ('repository', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='votes', to='common.Repository')), - ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='repository_votes', to=settings.AUTH_USER_MODEL)), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "vote", + models.IntegerField( + choices=[(1, "Up"), (-1, "Down"), (0, "Neutral")], + verbose_name="vote", + ), + ), + ( + "repository", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="votes", + to="common.Repository", + ), + ), + ( + "user", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="repository_votes", + to=settings.AUTH_USER_MODEL, + ), + ), ], options={ - 'verbose_name': 'repository vote', - 'verbose_name_plural': 'repository votes', + "verbose_name": "repository vote", + "verbose_name_plural": "repository votes", }, ), migrations.AlterUniqueTogether( - name='repositoryvote', - unique_together={('user', 'repository')}, + name="repositoryvote", unique_together={("user", "repository")} ), ] diff --git a/bothub/common/migrations/0010_auto_20180611_1123.py b/bothub/common/migrations/0010_auto_20180611_1123.py index baa5c99a..c7dbd3fc 100644 --- a/bothub/common/migrations/0010_auto_20180611_1123.py +++ b/bothub/common/migrations/0010_auto_20180611_1123.py @@ -7,24 +7,56 @@ class Migration(migrations.Migration): - dependencies = [ - ('common', '0009_auto_20180601_1348'), - ] + dependencies = [("common", "0009_auto_20180601_1348")] operations = [ migrations.AlterField( - model_name='repositoryexample', - name='intent', - field=models.CharField(blank=True, help_text='Example intent reference', max_length=64, validators=[django.core.validators.RegexValidator(re.compile('^[-a-z0-9_]+\\Z'), 'Enter a valid value consisting of lowercase letters, numbers, underscores or hyphens.', 'invalid')], verbose_name='intent'), + model_name="repositoryexample", + name="intent", + field=models.CharField( + blank=True, + help_text="Example intent reference", + max_length=64, + validators=[ + django.core.validators.RegexValidator( + re.compile("^[-a-z0-9_]+\\Z"), + "Enter a valid value consisting of lowercase letters, numbers, underscores or hyphens.", + "invalid", + ) + ], + verbose_name="intent", + ), ), migrations.AlterField( - model_name='repositoryexampleentity', - name='entity', - field=models.CharField(help_text='Entity name', max_length=64, validators=[django.core.validators.RegexValidator(re.compile('^[-a-z0-9_]+\\Z'), 'Enter a valid value consisting of lowercase letters, numbers, underscores or hyphens.', 'invalid')], verbose_name='entity'), + model_name="repositoryexampleentity", + name="entity", + field=models.CharField( + help_text="Entity name", + max_length=64, + validators=[ + django.core.validators.RegexValidator( + re.compile("^[-a-z0-9_]+\\Z"), + "Enter a valid value consisting of lowercase letters, numbers, underscores or hyphens.", + "invalid", + ) + ], + verbose_name="entity", + ), ), migrations.AlterField( - model_name='repositorytranslatedexampleentity', - name='entity', - field=models.CharField(help_text='Entity name', max_length=64, validators=[django.core.validators.RegexValidator(re.compile('^[-a-z0-9_]+\\Z'), 'Enter a valid value consisting of lowercase letters, numbers, underscores or hyphens.', 'invalid')], verbose_name='entity'), + model_name="repositorytranslatedexampleentity", + name="entity", + field=models.CharField( + help_text="Entity name", + max_length=64, + validators=[ + django.core.validators.RegexValidator( + re.compile("^[-a-z0-9_]+\\Z"), + "Enter a valid value consisting of lowercase letters, numbers, underscores or hyphens.", + "invalid", + ) + ], + verbose_name="entity", + ), ), ] diff --git a/bothub/common/migrations/0011_repositoryauthorization_role.py b/bothub/common/migrations/0011_repositoryauthorization_role.py index fd96afc8..67b300b1 100644 --- a/bothub/common/migrations/0011_repositoryauthorization_role.py +++ b/bothub/common/migrations/0011_repositoryauthorization_role.py @@ -5,14 +5,16 @@ class Migration(migrations.Migration): - dependencies = [ - ('common', '0010_auto_20180611_1123'), - ] + dependencies = [("common", "0010_auto_20180611_1123")] operations = [ migrations.AddField( - model_name='repositoryauthorization', - name='role', - field=models.PositiveIntegerField(choices=[(0, 'not set'), (1, 'user'), (2, 'contributor'), (3, 'admin')], default=0, verbose_name='role'), - ), + model_name="repositoryauthorization", + name="role", + field=models.PositiveIntegerField( + choices=[(0, "not set"), (1, "user"), (2, "contributor"), (3, "admin")], + default=0, + verbose_name="role", + ), + ) ] diff --git a/bothub/common/migrations/0012_auto_20180703_1931.py b/bothub/common/migrations/0012_auto_20180703_1931.py index f53f72f6..27158f94 100644 --- a/bothub/common/migrations/0012_auto_20180703_1931.py +++ b/bothub/common/migrations/0012_auto_20180703_1931.py @@ -9,23 +9,56 @@ class Migration(migrations.Migration): dependencies = [ migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ('common', '0011_repositoryauthorization_role'), + ("common", "0011_repositoryauthorization_role"), ] operations = [ migrations.CreateModel( - name='RequestRepositoryAuthorization', + name="RequestRepositoryAuthorization", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('text', models.CharField(max_length=250, verbose_name='text')), - ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='created at')), - ('approved_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), - ('repository', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='requests', to='common.Repository')), - ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='requests', to=settings.AUTH_USER_MODEL)), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("text", models.CharField(max_length=250, verbose_name="text")), + ( + "created_at", + models.DateTimeField(auto_now_add=True, verbose_name="created at"), + ), + ( + "approved_by", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + to=settings.AUTH_USER_MODEL, + ), + ), + ( + "repository", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="requests", + to="common.Repository", + ), + ), + ( + "user", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="requests", + to=settings.AUTH_USER_MODEL, + ), + ), ], ), migrations.AlterUniqueTogether( - name='requestrepositoryauthorization', - unique_together={('user', 'repository')}, + name="requestrepositoryauthorization", + unique_together={("user", "repository")}, ), ] diff --git a/bothub/common/migrations/0013_auto_20180706_1212.py b/bothub/common/migrations/0013_auto_20180706_1212.py index 1b9f2c9d..839b9a6a 100644 --- a/bothub/common/migrations/0013_auto_20180706_1212.py +++ b/bothub/common/migrations/0013_auto_20180706_1212.py @@ -6,14 +6,16 @@ class Migration(migrations.Migration): - dependencies = [ - ('common', '0012_auto_20180703_1931'), - ] + dependencies = [("common", "0012_auto_20180703_1931")] operations = [ migrations.AlterField( - model_name='repositoryauthorization', - name='repository', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='authorizations', to='common.Repository'), - ), + model_name="repositoryauthorization", + name="repository", + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="authorizations", + to="common.Repository", + ), + ) ] diff --git a/bothub/common/migrations/0014_auto_20180709_1909.py b/bothub/common/migrations/0014_auto_20180709_1909.py index 6765e4c9..5b01f008 100644 --- a/bothub/common/migrations/0014_auto_20180709_1909.py +++ b/bothub/common/migrations/0014_auto_20180709_1909.py @@ -6,24 +6,36 @@ class Migration(migrations.Migration): - dependencies = [ - ('common', '0013_auto_20180706_1212'), - ] + dependencies = [("common", "0013_auto_20180706_1212")] operations = [ migrations.AlterField( - model_name='repository', - name='language', - field=models.CharField(help_text="Repository's examples language. The examples can be translated to other languages.", max_length=2, validators=[bothub.common.languages.validate_language], verbose_name='language'), + model_name="repository", + name="language", + field=models.CharField( + help_text="Repository's examples language. The examples can be translated to other languages.", + max_length=2, + validators=[bothub.common.languages.validate_language], + verbose_name="language", + ), ), migrations.AlterField( - model_name='repositorytranslatedexample', - name='language', - field=models.CharField(help_text='Translation language', max_length=2, validators=[bothub.common.languages.validate_language], verbose_name='language'), + model_name="repositorytranslatedexample", + name="language", + field=models.CharField( + help_text="Translation language", + max_length=2, + validators=[bothub.common.languages.validate_language], + verbose_name="language", + ), ), migrations.AlterField( - model_name='repositoryupdate', - name='language', - field=models.CharField(max_length=2, validators=[bothub.common.languages.validate_language], verbose_name='language'), + model_name="repositoryupdate", + name="language", + field=models.CharField( + max_length=2, + validators=[bothub.common.languages.validate_language], + verbose_name="language", + ), ), ] diff --git a/bothub/common/migrations/0015_auto_20180712_2130.py b/bothub/common/migrations/0015_auto_20180712_2130.py index c28e75e8..7755fbad 100644 --- a/bothub/common/migrations/0015_auto_20180712_2130.py +++ b/bothub/common/migrations/0015_auto_20180712_2130.py @@ -6,14 +6,17 @@ class Migration(migrations.Migration): - dependencies = [ - ('common', '0014_auto_20180709_1909'), - ] + dependencies = [("common", "0014_auto_20180709_1909")] operations = [ migrations.AlterField( - model_name='repository', - name='language', - field=models.CharField(help_text="Repository's examples language. The examples can be translated to other languages.", max_length=5, validators=[bothub.common.languages.validate_language], verbose_name='language'), - ), + model_name="repository", + name="language", + field=models.CharField( + help_text="Repository's examples language. The examples can be translated to other languages.", + max_length=5, + validators=[bothub.common.languages.validate_language], + verbose_name="language", + ), + ) ] diff --git a/bothub/common/migrations/0016_auto_20180712_2131.py b/bothub/common/migrations/0016_auto_20180712_2131.py index 8a2f0a8e..1faa6861 100644 --- a/bothub/common/migrations/0016_auto_20180712_2131.py +++ b/bothub/common/migrations/0016_auto_20180712_2131.py @@ -6,14 +6,16 @@ class Migration(migrations.Migration): - dependencies = [ - ('common', '0015_auto_20180712_2130'), - ] + dependencies = [("common", "0015_auto_20180712_2130")] operations = [ migrations.AlterField( - model_name='repositoryupdate', - name='language', - field=models.CharField(max_length=5, validators=[bothub.common.languages.validate_language], verbose_name='language'), - ), + model_name="repositoryupdate", + name="language", + field=models.CharField( + max_length=5, + validators=[bothub.common.languages.validate_language], + verbose_name="language", + ), + ) ] diff --git a/bothub/common/migrations/0017_auto_20180712_2131.py b/bothub/common/migrations/0017_auto_20180712_2131.py index 382eef75..9e0d00cb 100644 --- a/bothub/common/migrations/0017_auto_20180712_2131.py +++ b/bothub/common/migrations/0017_auto_20180712_2131.py @@ -6,14 +6,17 @@ class Migration(migrations.Migration): - dependencies = [ - ('common', '0016_auto_20180712_2131'), - ] + dependencies = [("common", "0016_auto_20180712_2131")] operations = [ migrations.AlterField( - model_name='repositorytranslatedexample', - name='language', - field=models.CharField(help_text='Translation language', max_length=5, validators=[bothub.common.languages.validate_language], verbose_name='language'), - ), + model_name="repositorytranslatedexample", + name="language", + field=models.CharField( + help_text="Translation language", + max_length=5, + validators=[bothub.common.languages.validate_language], + verbose_name="language", + ), + ) ] diff --git a/bothub/common/migrations/0018_auto_20180725_1305.py b/bothub/common/migrations/0018_auto_20180725_1305.py index 16276783..37b9ee5e 100644 --- a/bothub/common/migrations/0018_auto_20180725_1305.py +++ b/bothub/common/migrations/0018_auto_20180725_1305.py @@ -7,53 +7,88 @@ def populate_example_entities(apps, *args): - RepositoryExampleEntity = apps.get_model('common', 'RepositoryExampleEntity') - RepositoryTranslatedExampleEntity = apps.get_model('common', 'RepositoryTranslatedExampleEntity') - RepositoryEntity = apps.get_model('common', 'RepositoryEntity') + RepositoryExampleEntity = apps.get_model("common", "RepositoryExampleEntity") + RepositoryTranslatedExampleEntity = apps.get_model( + "common", "RepositoryTranslatedExampleEntity" + ) + RepositoryEntity = apps.get_model("common", "RepositoryEntity") for e in RepositoryExampleEntity.objects.all(): entity, create = RepositoryEntity.objects.get_or_create( - repository=e.repository_example.repository_update.repository, - value=e.entity) + repository=e.repository_example.repository_update.repository, value=e.entity + ) e.entity = entity.pk e.save() for e in RepositoryTranslatedExampleEntity.objects.all(): entity, create = RepositoryEntity.objects.get_or_create( repository=e.repository_translated_example.repository_update.repository, - value=e.entity) + value=e.entity, + ) e.entity = entity.pk e.save() class Migration(migrations.Migration): - dependencies = [ - ('common', '0017_auto_20180712_2131'), - ] + dependencies = [("common", "0017_auto_20180712_2131")] operations = [ migrations.CreateModel( - name='RepositoryEntity', + name="RepositoryEntity", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('value', models.CharField(help_text='Entity name', max_length=64, validators=[django.core.validators.RegexValidator(re.compile('^[-a-z0-9_]+\\Z'), 'Enter a valid value consisting of lowercase letters, numbers, underscores or hyphens.', 'invalid')], verbose_name='entity')), - ('repository', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='entities', to='common.Repository')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "value", + models.CharField( + help_text="Entity name", + max_length=64, + validators=[ + django.core.validators.RegexValidator( + re.compile("^[-a-z0-9_]+\\Z"), + "Enter a valid value consisting of lowercase letters, numbers, underscores or hyphens.", + "invalid", + ) + ], + verbose_name="entity", + ), + ), + ( + "repository", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="entities", + to="common.Repository", + ), + ), ], ), migrations.RunPython(populate_example_entities), migrations.AlterField( - model_name='repositoryexampleentity', - name='entity', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='common.RepositoryEntity'), + model_name="repositoryexampleentity", + name="entity", + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="common.RepositoryEntity", + ), ), migrations.AlterField( - model_name='repositorytranslatedexampleentity', - name='entity', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='common.RepositoryEntity'), + model_name="repositorytranslatedexampleentity", + name="entity", + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="common.RepositoryEntity", + ), ), migrations.AlterUniqueTogether( - name='repositoryentity', - unique_together={('repository', 'value')}, + name="repositoryentity", unique_together={("repository", "value")} ), ] diff --git a/bothub/common/migrations/0019_auto_20180725_1657.py b/bothub/common/migrations/0019_auto_20180725_1657.py index f5a64ccc..f83a8a51 100644 --- a/bothub/common/migrations/0019_auto_20180725_1657.py +++ b/bothub/common/migrations/0019_auto_20180725_1657.py @@ -9,33 +9,72 @@ class Migration(migrations.Migration): - dependencies = [ - ('common', '0018_auto_20180725_1305'), - ] + dependencies = [("common", "0018_auto_20180725_1305")] operations = [ migrations.CreateModel( - name='RepositoryEntityLabel', + name="RepositoryEntityLabel", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('value', models.CharField(blank=True, max_length=64, validators=[django.core.validators.RegexValidator(re.compile('^[-a-z0-9_]+\\Z'), 'Enter a valid value consisting of lowercase letters, numbers, underscores or hyphens.', 'invalid')], verbose_name='label')), - ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='created at')), - ('repository', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='labels', to='common.Repository')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "value", + models.CharField( + blank=True, + max_length=64, + validators=[ + django.core.validators.RegexValidator( + re.compile("^[-a-z0-9_]+\\Z"), + "Enter a valid value consisting of lowercase letters, numbers, underscores or hyphens.", + "invalid", + ) + ], + verbose_name="label", + ), + ), + ( + "created_at", + models.DateTimeField(auto_now_add=True, verbose_name="created at"), + ), + ( + "repository", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="labels", + to="common.Repository", + ), + ), ], ), migrations.AddField( - model_name='repositoryentity', - name='created_at', - field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now, verbose_name='created at'), + model_name="repositoryentity", + name="created_at", + field=models.DateTimeField( + auto_now_add=True, + default=django.utils.timezone.now, + verbose_name="created at", + ), preserve_default=False, ), migrations.AddField( - model_name='repositoryentity', - name='label', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='entities', to='common.RepositoryEntityLabel'), + model_name="repositoryentity", + name="label", + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="entities", + to="common.RepositoryEntityLabel", + ), ), migrations.AlterUniqueTogether( - name='repositoryentitylabel', - unique_together={('repository', 'value')}, + name="repositoryentitylabel", unique_together={("repository", "value")} ), ] diff --git a/bothub/common/migrations/0020_auto_20180813_1320.py b/bothub/common/migrations/0020_auto_20180813_1320.py index ebe2eb38..e2fee9f5 100644 --- a/bothub/common/migrations/0020_auto_20180813_1320.py +++ b/bothub/common/migrations/0020_auto_20180813_1320.py @@ -8,14 +8,24 @@ class Migration(migrations.Migration): - dependencies = [ - ('common', '0019_auto_20180725_1657'), - ] + dependencies = [("common", "0019_auto_20180725_1657")] operations = [ migrations.AlterField( - model_name='repositoryentitylabel', - name='value', - field=models.CharField(blank=True, max_length=64, validators=[django.core.validators.RegexValidator(re.compile('^[-a-z0-9_]+\\Z'), 'Enter a valid value consisting of lowercase letters, numbers, underscores or hyphens.', 'invalid'), bothub.common.models.can_t_be_other], verbose_name='label'), - ), + model_name="repositoryentitylabel", + name="value", + field=models.CharField( + blank=True, + max_length=64, + validators=[ + django.core.validators.RegexValidator( + re.compile("^[-a-z0-9_]+\\Z"), + "Enter a valid value consisting of lowercase letters, numbers, underscores or hyphens.", + "invalid", + ), + bothub.common.models.can_t_be_other, + ], + verbose_name="label", + ), + ) ] diff --git a/bothub/common/migrations/0021_auto_20180921_1259.py b/bothub/common/migrations/0021_auto_20180921_1259.py index b44f4046..00291c4d 100644 --- a/bothub/common/migrations/0021_auto_20180921_1259.py +++ b/bothub/common/migrations/0021_auto_20180921_1259.py @@ -6,21 +6,31 @@ def populate_empty_intent(apps, *args): - RepositoryExample = apps.get_model('common', 'RepositoryExample') - RepositoryExample.objects.filter(intent='').update(intent='no_intent') + RepositoryExample = apps.get_model("common", "RepositoryExample") + RepositoryExample.objects.filter(intent="").update(intent="no_intent") class Migration(migrations.Migration): - dependencies = [ - ('common', '0020_auto_20180813_1320'), - ] + dependencies = [("common", "0020_auto_20180813_1320")] operations = [ migrations.AlterField( - model_name='repositoryexample', - name='intent', - field=models.CharField(default='no_intent', help_text='Example intent reference', max_length=64, validators=[django.core.validators.RegexValidator(re.compile('^[-a-z0-9_]+\\Z'), 'Enter a valid value consisting of lowercase letters, numbers, underscores or hyphens.', 'invalid')], verbose_name='intent'), + model_name="repositoryexample", + name="intent", + field=models.CharField( + default="no_intent", + help_text="Example intent reference", + max_length=64, + validators=[ + django.core.validators.RegexValidator( + re.compile("^[-a-z0-9_]+\\Z"), + "Enter a valid value consisting of lowercase letters, numbers, underscores or hyphens.", + "invalid", + ) + ], + verbose_name="intent", + ), ), migrations.RunPython(populate_empty_intent), ] diff --git a/bothub/common/migrations/0022_repositoryupdate_training_log.py b/bothub/common/migrations/0022_repositoryupdate_training_log.py index a489cf5e..b04add91 100644 --- a/bothub/common/migrations/0022_repositoryupdate_training_log.py +++ b/bothub/common/migrations/0022_repositoryupdate_training_log.py @@ -5,14 +5,14 @@ class Migration(migrations.Migration): - dependencies = [ - ('common', '0021_auto_20180921_1259'), - ] + dependencies = [("common", "0021_auto_20180921_1259")] operations = [ migrations.AddField( - model_name='repositoryupdate', - name='training_log', - field=models.TextField(blank=True, editable=False, verbose_name='training log'), - ), + model_name="repositoryupdate", + name="training_log", + field=models.TextField( + blank=True, editable=False, verbose_name="training log" + ), + ) ] diff --git a/bothub/common/migrations/0023_repository_use_language_model_featurizer.py b/bothub/common/migrations/0023_repository_use_language_model_featurizer.py index cb1c91f4..9f76e3a6 100644 --- a/bothub/common/migrations/0023_repository_use_language_model_featurizer.py +++ b/bothub/common/migrations/0023_repository_use_language_model_featurizer.py @@ -5,14 +5,16 @@ class Migration(migrations.Migration): - dependencies = [ - ('common', '0022_repositoryupdate_training_log'), - ] + dependencies = [("common", "0022_repositoryupdate_training_log")] operations = [ migrations.AddField( - model_name='repository', - name='use_language_model_featurizer', - field=models.BooleanField(default=True, help_text='You can use language featurizer to get words similarity. You need less examples to create a great bot.', verbose_name='Use language model featurizer'), - ), + model_name="repository", + name="use_language_model_featurizer", + field=models.BooleanField( + default=True, + help_text="You can use language featurizer to get words similarity. You need less examples to create a great bot.", + verbose_name="Use language model featurizer", + ), + ) ] diff --git a/bothub/common/migrations/0024_repositoryupdate_use_language_model_featurizer.py b/bothub/common/migrations/0024_repositoryupdate_use_language_model_featurizer.py index 7343fe2f..5e6142cd 100644 --- a/bothub/common/migrations/0024_repositoryupdate_use_language_model_featurizer.py +++ b/bothub/common/migrations/0024_repositoryupdate_use_language_model_featurizer.py @@ -5,14 +5,12 @@ class Migration(migrations.Migration): - dependencies = [ - ('common', '0023_repository_use_language_model_featurizer'), - ] + dependencies = [("common", "0023_repository_use_language_model_featurizer")] operations = [ migrations.AddField( - model_name='repositoryupdate', - name='use_language_model_featurizer', + model_name="repositoryupdate", + name="use_language_model_featurizer", field=models.BooleanField(default=True), - ), + ) ] diff --git a/bothub/common/migrations/0025_auto_20181003_1911.py b/bothub/common/migrations/0025_auto_20181003_1911.py index f86d83c2..890f34e2 100644 --- a/bothub/common/migrations/0025_auto_20181003_1911.py +++ b/bothub/common/migrations/0025_auto_20181003_1911.py @@ -5,19 +5,21 @@ class Migration(migrations.Migration): - dependencies = [ - ('common', '0024_repositoryupdate_use_language_model_featurizer'), - ] + dependencies = [("common", "0024_repositoryupdate_use_language_model_featurizer")] operations = [ migrations.AddField( - model_name='repository', - name='use_competing_intents', - field=models.BooleanField(default=False, help_text='When using competing intents the confidence of the prediction is distributed in all the intents.', verbose_name='Use competing intents'), + model_name="repository", + name="use_competing_intents", + field=models.BooleanField( + default=False, + help_text="When using competing intents the confidence of the prediction is distributed in all the intents.", + verbose_name="Use competing intents", + ), ), migrations.AddField( - model_name='repositoryupdate', - name='use_competing_intents', + model_name="repositoryupdate", + name="use_competing_intents", field=models.BooleanField(default=False), ), ] diff --git a/bothub/common/migrations/0026_auto_20181010_1704.py b/bothub/common/migrations/0026_auto_20181010_1704.py index 7e860037..465d9577 100644 --- a/bothub/common/migrations/0026_auto_20181010_1704.py +++ b/bothub/common/migrations/0026_auto_20181010_1704.py @@ -7,14 +7,16 @@ class Migration(migrations.Migration): - dependencies = [ - ('common', '0025_auto_20181003_1911'), - ] + dependencies = [("common", "0025_auto_20181003_1911")] operations = [ migrations.AlterField( - model_name='repository', - name='owner', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='repositories', to=settings.AUTH_USER_MODEL), - ), + model_name="repository", + name="owner", + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="repositories", + to=settings.AUTH_USER_MODEL, + ), + ) ] diff --git a/bothub/common/migrations/0027_repositorycategory_icon.py b/bothub/common/migrations/0027_repositorycategory_icon.py index ccc65153..58ee44de 100644 --- a/bothub/common/migrations/0027_repositorycategory_icon.py +++ b/bothub/common/migrations/0027_repositorycategory_icon.py @@ -5,14 +5,14 @@ class Migration(migrations.Migration): - dependencies = [ - ('common', '0026_auto_20181010_1704'), - ] + dependencies = [("common", "0026_auto_20181010_1704")] operations = [ migrations.AddField( - model_name='repositorycategory', - name='icon', - field=models.CharField(default='botinho', max_length=16, verbose_name='icon'), - ), + model_name="repositorycategory", + name="icon", + field=models.CharField( + default="botinho", max_length=16, verbose_name="icon" + ), + ) ] diff --git a/bothub/common/migrations/0028_auto_20190121_1250.py b/bothub/common/migrations/0028_auto_20190121_1250.py index 1491eed0..a67a7965 100644 --- a/bothub/common/migrations/0028_auto_20190121_1250.py +++ b/bothub/common/migrations/0028_auto_20190121_1250.py @@ -5,19 +5,47 @@ class Migration(migrations.Migration): - dependencies = [ - ('common', '0027_repositorycategory_icon'), - ] + dependencies = [("common", "0027_repositorycategory_icon")] operations = [ migrations.AddField( - model_name='repository', - name='algorithm', - field=models.CharField(choices=[('statistical_model', 'Statistical Model'), ('neural_network_internal', 'Neural Network with internal vocabulary'), ('neural_network_external', 'Neural Network with external vocabulary (BETA)')], default='statistical_model', max_length=24, verbose_name='algorithm'), + model_name="repository", + name="algorithm", + field=models.CharField( + choices=[ + ("statistical_model", "Statistical Model"), + ( + "neural_network_internal", + "Neural Network with internal vocabulary", + ), + ( + "neural_network_external", + "Neural Network with external vocabulary (BETA)", + ), + ], + default="statistical_model", + max_length=24, + verbose_name="algorithm", + ), ), migrations.AddField( - model_name='repositoryupdate', - name='algorithm', - field=models.CharField(choices=[('statistical_model', 'Statistical Model'), ('neural_network_internal', 'Neural Network with internal vocabulary'), ('neural_network_external', 'Neural Network with external vocabulary (BETA)')], default='statistical_model', max_length=24, verbose_name='algorithm'), + model_name="repositoryupdate", + name="algorithm", + field=models.CharField( + choices=[ + ("statistical_model", "Statistical Model"), + ( + "neural_network_internal", + "Neural Network with internal vocabulary", + ), + ( + "neural_network_external", + "Neural Network with external vocabulary (BETA)", + ), + ], + default="statistical_model", + max_length=24, + verbose_name="algorithm", + ), ), ] diff --git a/bothub/common/migrations/0029_auto_20190126_0247.py b/bothub/common/migrations/0029_auto_20190126_0247.py index 9694731d..57c3f6f9 100644 --- a/bothub/common/migrations/0029_auto_20190126_0247.py +++ b/bothub/common/migrations/0029_auto_20190126_0247.py @@ -5,34 +5,34 @@ def populate_algorithm(apps, *args): from bothub.common.models import Repository as R - Repository = apps.get_model('common', 'Repository') + + Repository = apps.get_model("common", "Repository") for repository in Repository.objects.all(): - repository.algorithm = R.ALGORITHM_NEURAL_NETWORK_EXTERNAL \ - if repository.use_language_model_featurizer else \ - R.ALGORITHM_NEURAL_NETWORK_INTERNAL - repository.save(update_fields=['algorithm']) + repository.algorithm = ( + R.ALGORITHM_NEURAL_NETWORK_EXTERNAL + if repository.use_language_model_featurizer + else R.ALGORITHM_NEURAL_NETWORK_INTERNAL + ) + repository.save(update_fields=["algorithm"]) for update in repository.updates.all(): - update.algorithm = R.ALGORITHM_NEURAL_NETWORK_EXTERNAL \ - if update.use_language_model_featurizer else \ - R.ALGORITHM_NEURAL_NETWORK_INTERNAL - update.save(update_fields=['algorithm']) + update.algorithm = ( + R.ALGORITHM_NEURAL_NETWORK_EXTERNAL + if update.use_language_model_featurizer + else R.ALGORITHM_NEURAL_NETWORK_INTERNAL + ) + update.save(update_fields=["algorithm"]) class Migration(migrations.Migration): - dependencies = [ - ('common', '0028_auto_20190121_1250'), - ] + dependencies = [("common", "0028_auto_20190121_1250")] operations = [ migrations.RunPython(populate_algorithm), migrations.RemoveField( - model_name='repository', - name='use_language_model_featurizer', + model_name="repository", name="use_language_model_featurizer" ), migrations.RemoveField( - model_name='repositoryupdate', - name='use_language_model_featurizer', + model_name="repositoryupdate", name="use_language_model_featurizer" ), ] - diff --git a/bothub/common/migrations/0030_auto_20190327_2003.py b/bothub/common/migrations/0030_auto_20190327_2003.py index 50acab40..bf5cb297 100644 --- a/bothub/common/migrations/0030_auto_20190327_2003.py +++ b/bothub/common/migrations/0030_auto_20190327_2003.py @@ -5,19 +5,21 @@ class Migration(migrations.Migration): - dependencies = [ - ('common', '0029_auto_20190126_0247'), - ] + dependencies = [("common", "0029_auto_20190126_0247")] operations = [ migrations.AddField( - model_name='repository', - name='use_name_entities', - field=models.BooleanField(default=False, help_text='When enabling name entities you will receive name of people, companies and places as results of your predictions.', verbose_name='Use name entities'), + model_name="repository", + name="use_name_entities", + field=models.BooleanField( + default=False, + help_text="When enabling name entities you will receive name of people, companies and places as results of your predictions.", + verbose_name="Use name entities", + ), ), migrations.AddField( - model_name='repositoryupdate', - name='use_name_entities', + model_name="repositoryupdate", + name="use_name_entities", field=models.BooleanField(default=False), ), ] diff --git a/bothub/common/migrations/0031_auto_20190502_1732.py b/bothub/common/migrations/0031_auto_20190502_1732.py index 6fbf3161..3010560f 100644 --- a/bothub/common/migrations/0031_auto_20190502_1732.py +++ b/bothub/common/migrations/0031_auto_20190502_1732.py @@ -8,120 +8,330 @@ class Migration(migrations.Migration): - dependencies = [ - ('common', '0030_auto_20190327_2003'), - ] + dependencies = [("common", "0030_auto_20190327_2003")] operations = [ migrations.CreateModel( - name='RepositoryEvaluate', + name="RepositoryEvaluate", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('text', models.TextField(help_text='Evaluate test text', verbose_name='text')), - ('intent', models.CharField(default='no_intent', help_text='Evaluate intent reference', max_length=64, validators=[django.core.validators.RegexValidator(re.compile('^[-a-z0-9_]+\\Z'), 'Enter a valid value consisting of lowercase letters, numbers, underscores or hyphens.', 'invalid')], verbose_name='intent')), - ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='created at')), - ('deleted_in', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='deleted_evaluate', to='common.RepositoryUpdate')), - ('repository_update', models.ForeignKey(editable=False, on_delete=django.db.models.deletion.CASCADE, related_name='added_evaluate', to='common.RepositoryUpdate')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "text", + models.TextField( + help_text="Evaluate test text", verbose_name="text" + ), + ), + ( + "intent", + models.CharField( + default="no_intent", + help_text="Evaluate intent reference", + max_length=64, + validators=[ + django.core.validators.RegexValidator( + re.compile("^[-a-z0-9_]+\\Z"), + "Enter a valid value consisting of lowercase letters, numbers, underscores or hyphens.", + "invalid", + ) + ], + verbose_name="intent", + ), + ), + ( + "created_at", + models.DateTimeField(auto_now_add=True, verbose_name="created at"), + ), + ( + "deleted_in", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="deleted_evaluate", + to="common.RepositoryUpdate", + ), + ), + ( + "repository_update", + models.ForeignKey( + editable=False, + on_delete=django.db.models.deletion.CASCADE, + related_name="added_evaluate", + to="common.RepositoryUpdate", + ), + ), ], options={ - 'verbose_name': 'repository evaluate test', - 'verbose_name_plural': 'repository evaluate tests', - 'db_table': 'common_repository_evaluate', - 'ordering': ['-created_at'], + "verbose_name": "repository evaluate test", + "verbose_name_plural": "repository evaluate tests", + "db_table": "common_repository_evaluate", + "ordering": ["-created_at"], }, ), migrations.CreateModel( - name='RepositoryEvaluateEntity', + name="RepositoryEvaluateEntity", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('start', models.PositiveIntegerField(help_text='Start index of entity value in example text', verbose_name='start')), - ('end', models.PositiveIntegerField(help_text='End index of entity value in example text', verbose_name='end')), - ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='created at')), - ('entity', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='common.RepositoryEntity')), - ('repository_evaluate', models.ForeignKey(editable=False, help_text='evaluate object', on_delete=django.db.models.deletion.CASCADE, related_name='entities', to='common.RepositoryEvaluate')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "start", + models.PositiveIntegerField( + help_text="Start index of entity value in example text", + verbose_name="start", + ), + ), + ( + "end", + models.PositiveIntegerField( + help_text="End index of entity value in example text", + verbose_name="end", + ), + ), + ( + "created_at", + models.DateTimeField(auto_now_add=True, verbose_name="created at"), + ), + ( + "entity", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="common.RepositoryEntity", + ), + ), + ( + "repository_evaluate", + models.ForeignKey( + editable=False, + help_text="evaluate object", + on_delete=django.db.models.deletion.CASCADE, + related_name="entities", + to="common.RepositoryEvaluate", + ), + ), ], - options={ - 'db_table': 'common_repository_evaluate_entity', - }, + options={"db_table": "common_repository_evaluate_entity"}, ), migrations.CreateModel( - name='RepositoryEvaluateResult', + name="RepositoryEvaluateResult", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('matrix_chart', models.URLField(editable=False, verbose_name='Intent Confusion Matrix Chart')), - ('confidence_chart', models.URLField(editable=False, verbose_name='Intent Prediction Confidence Distribution')), - ('log', models.TextField(blank=True, editable=False, verbose_name='Evaluate Log')), - ('version', models.IntegerField(default=0, editable=False, verbose_name='Version')), - ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='created at')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "matrix_chart", + models.URLField( + editable=False, verbose_name="Intent Confusion Matrix Chart" + ), + ), + ( + "confidence_chart", + models.URLField( + editable=False, + verbose_name="Intent Prediction Confidence Distribution", + ), + ), + ( + "log", + models.TextField( + blank=True, editable=False, verbose_name="Evaluate Log" + ), + ), + ( + "version", + models.IntegerField( + default=0, editable=False, verbose_name="Version" + ), + ), + ( + "created_at", + models.DateTimeField(auto_now_add=True, verbose_name="created at"), + ), ], options={ - 'verbose_name': 'evaluate results', - 'verbose_name_plural': 'evaluate results', - 'db_table': 'common_repository_evaluate_result', - 'ordering': ['-created_at'], + "verbose_name": "evaluate results", + "verbose_name_plural": "evaluate results", + "db_table": "common_repository_evaluate_result", + "ordering": ["-created_at"], }, ), migrations.CreateModel( - name='RepositoryEvaluateResultEntity', + name="RepositoryEvaluateResultEntity", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('entity', models.ForeignKey(editable=False, on_delete=django.db.models.deletion.CASCADE, related_name='entity', to='common.RepositoryEntity')), - ('evaluate_result', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='evaluate_result_entity', to='common.RepositoryEvaluateResult')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "entity", + models.ForeignKey( + editable=False, + on_delete=django.db.models.deletion.CASCADE, + related_name="entity", + to="common.RepositoryEntity", + ), + ), + ( + "evaluate_result", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="evaluate_result_entity", + to="common.RepositoryEvaluateResult", + ), + ), ], - options={ - 'db_table': 'common_repository_evaluate_result_entity', - }, + options={"db_table": "common_repository_evaluate_result_entity"}, ), migrations.CreateModel( - name='RepositoryEvaluateResultIntent', + name="RepositoryEvaluateResultIntent", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('intent', models.CharField(help_text='Evaluate intent reference', max_length=64, validators=[django.core.validators.RegexValidator(re.compile('^[-a-z0-9_]+\\Z'), 'Enter a valid value consisting of lowercase letters, numbers, underscores or hyphens.', 'invalid')], verbose_name='intent')), - ('evaluate_result', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='evaluate_result_intent', to='common.RepositoryEvaluateResult')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "intent", + models.CharField( + help_text="Evaluate intent reference", + max_length=64, + validators=[ + django.core.validators.RegexValidator( + re.compile("^[-a-z0-9_]+\\Z"), + "Enter a valid value consisting of lowercase letters, numbers, underscores or hyphens.", + "invalid", + ) + ], + verbose_name="intent", + ), + ), + ( + "evaluate_result", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="evaluate_result_intent", + to="common.RepositoryEvaluateResult", + ), + ), ], - options={ - 'db_table': 'common_repository_evaluate_result_intent', - }, + options={"db_table": "common_repository_evaluate_result_intent"}, ), migrations.CreateModel( - name='RepositoryEvaluateResultScore', + name="RepositoryEvaluateResultScore", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('precision', models.DecimalField(decimal_places=2, max_digits=3, null=True)), - ('f1_score', models.DecimalField(decimal_places=2, max_digits=3, null=True)), - ('accuracy', models.DecimalField(decimal_places=2, max_digits=3, null=True)), - ('recall', models.DecimalField(decimal_places=2, max_digits=3, null=True)), - ('support', models.IntegerField(null=True)), - ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='created at')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "precision", + models.DecimalField(decimal_places=2, max_digits=3, null=True), + ), + ( + "f1_score", + models.DecimalField(decimal_places=2, max_digits=3, null=True), + ), + ( + "accuracy", + models.DecimalField(decimal_places=2, max_digits=3, null=True), + ), + ( + "recall", + models.DecimalField(decimal_places=2, max_digits=3, null=True), + ), + ("support", models.IntegerField(null=True)), + ( + "created_at", + models.DateTimeField(auto_now_add=True, verbose_name="created at"), + ), ], options={ - 'db_table': 'common_repository_evaluate_result_score', - 'ordering': ['-created_at'], + "db_table": "common_repository_evaluate_result_score", + "ordering": ["-created_at"], }, ), migrations.AddField( - model_name='repositoryevaluateresultintent', - name='score', - field=models.ForeignKey(editable=False, on_delete=django.db.models.deletion.CASCADE, related_name='evaluation_intenties_score', to='common.RepositoryEvaluateResultScore'), + model_name="repositoryevaluateresultintent", + name="score", + field=models.ForeignKey( + editable=False, + on_delete=django.db.models.deletion.CASCADE, + related_name="evaluation_intenties_score", + to="common.RepositoryEvaluateResultScore", + ), ), migrations.AddField( - model_name='repositoryevaluateresultentity', - name='score', - field=models.ForeignKey(editable=False, on_delete=django.db.models.deletion.CASCADE, related_name='evaluation_entities_score', to='common.RepositoryEvaluateResultScore'), + model_name="repositoryevaluateresultentity", + name="score", + field=models.ForeignKey( + editable=False, + on_delete=django.db.models.deletion.CASCADE, + related_name="evaluation_entities_score", + to="common.RepositoryEvaluateResultScore", + ), ), migrations.AddField( - model_name='repositoryevaluateresult', - name='entity_results', - field=models.ForeignKey(editable=False, on_delete=django.db.models.deletion.CASCADE, related_name='entity_results', to='common.RepositoryEvaluateResultScore'), + model_name="repositoryevaluateresult", + name="entity_results", + field=models.ForeignKey( + editable=False, + on_delete=django.db.models.deletion.CASCADE, + related_name="entity_results", + to="common.RepositoryEvaluateResultScore", + ), ), migrations.AddField( - model_name='repositoryevaluateresult', - name='intent_results', - field=models.ForeignKey(editable=False, on_delete=django.db.models.deletion.CASCADE, related_name='intent_results', to='common.RepositoryEvaluateResultScore'), + model_name="repositoryevaluateresult", + name="intent_results", + field=models.ForeignKey( + editable=False, + on_delete=django.db.models.deletion.CASCADE, + related_name="intent_results", + to="common.RepositoryEvaluateResultScore", + ), ), migrations.AddField( - model_name='repositoryevaluateresult', - name='repository_update', - field=models.ForeignKey(editable=False, on_delete=django.db.models.deletion.CASCADE, related_name='results', to='common.RepositoryUpdate'), + model_name="repositoryevaluateresult", + name="repository_update", + field=models.ForeignKey( + editable=False, + on_delete=django.db.models.deletion.CASCADE, + related_name="results", + to="common.RepositoryUpdate", + ), ), ] diff --git a/bothub/common/migrations/0032_repository_total_updates.py b/bothub/common/migrations/0032_repository_total_updates.py index 77b7f9ab..e57dd2de 100644 --- a/bothub/common/migrations/0032_repository_total_updates.py +++ b/bothub/common/migrations/0032_repository_total_updates.py @@ -7,9 +7,7 @@ def updateRepository(apps, schema_editor): - for update in RepositoryUpdate.objects.all().filter( - trained_at__isnull=False - ): + for update in RepositoryUpdate.objects.all().filter(trained_at__isnull=False): repository = Repository.objects.get(uuid=update.repository.uuid) repository.total_updates += 1 repository.save() @@ -17,15 +15,13 @@ def updateRepository(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ - ('common', '0031_auto_20190502_1732'), - ] + dependencies = [("common", "0031_auto_20190502_1732")] operations = [ migrations.AddField( - model_name='repository', - name='total_updates', - field=models.IntegerField(default=0, verbose_name='total updates'), + model_name="repository", + name="total_updates", + field=models.IntegerField(default=0, verbose_name="total updates"), ), migrations.RunPython(updateRepository), ] diff --git a/bothub/common/migrations/0033_auto_20190816_2030.py b/bothub/common/migrations/0033_auto_20190816_2030.py index f6de4417..2f26debe 100644 --- a/bothub/common/migrations/0033_auto_20190816_2030.py +++ b/bothub/common/migrations/0033_auto_20190816_2030.py @@ -6,19 +6,16 @@ class Migration(migrations.Migration): - dependencies = [ - ('common', '0032_repository_total_updates'), - ] + dependencies = [("common", "0032_repository_total_updates")] operations = [ - migrations.RemoveField( - model_name='repositoryvote', - name='vote', - ), + migrations.RemoveField(model_name="repositoryvote", name="vote"), migrations.AddField( - model_name='repositoryvote', - name='created', - field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now), + model_name="repositoryvote", + name="created", + field=models.DateTimeField( + auto_now_add=True, default=django.utils.timezone.now + ), preserve_default=False, ), ] diff --git a/bothub/common/migrations/0034_repository_nlp_server.py b/bothub/common/migrations/0034_repository_nlp_server.py index bf417908..8c6ef05f 100644 --- a/bothub/common/migrations/0034_repository_nlp_server.py +++ b/bothub/common/migrations/0034_repository_nlp_server.py @@ -5,14 +5,12 @@ class Migration(migrations.Migration): - dependencies = [ - ('common', '0033_auto_20190816_2030'), - ] + dependencies = [("common", "0033_auto_20190816_2030")] operations = [ migrations.AddField( - model_name='repository', - name='nlp_server', - field=models.URLField(blank=True, null=True, verbose_name='Base URL NLP'), - ), + model_name="repository", + name="nlp_server", + field=models.URLField(blank=True, null=True, verbose_name="Base URL NLP"), + ) ] diff --git a/bothub/common/migrations/0035_auto_20190902_1455.py b/bothub/common/migrations/0035_auto_20190902_1455.py index f1cef359..826e3b8a 100644 --- a/bothub/common/migrations/0035_auto_20190902_1455.py +++ b/bothub/common/migrations/0035_auto_20190902_1455.py @@ -6,28 +6,23 @@ def update_repository(apps, schema_editor): - for update in RepositoryUpdate.objects.all().exclude(bot_data__exact=''): + for update in RepositoryUpdate.objects.all().exclude(bot_data__exact=""): url = send_bot_data_file_aws(update.pk, update.bot_data) repository_update = RepositoryUpdate.objects.get(pk=update.pk) repository_update.bot_data = url - repository_update.save( - update_fields=[ - 'bot_data', - ]) - print('Updating bot_data repository_update {}'.format(str(update.pk))) + repository_update.save(update_fields=["bot_data"]) + print("Updating bot_data repository_update {}".format(str(update.pk))) class Migration(migrations.Migration): - dependencies = [ - ('common', '0034_repository_nlp_server'), - ] + dependencies = [("common", "0034_repository_nlp_server")] operations = [ migrations.RunPython(update_repository), migrations.AlterField( - model_name='repositoryupdate', - name='bot_data', - field=models.URLField(blank=True, verbose_name='bot data'), + model_name="repositoryupdate", + name="bot_data", + field=models.URLField(blank=True, verbose_name="bot data"), ), ] diff --git a/bothub/common/models.py b/bothub/common/models.py index 0c593b01..7ac4f663 100644 --- a/bothub/common/models.py +++ b/bothub/common/models.py @@ -23,32 +23,29 @@ from .exceptions import DoesNotHaveTranslation -item_key_regex = _lazy_re_compile(r'^[-a-z0-9_]+\Z') +item_key_regex = _lazy_re_compile(r"^[-a-z0-9_]+\Z") validate_item_key = RegexValidator( item_key_regex, - _('Enter a valid value consisting of lowercase letters, numbers, ' + - 'underscores or hyphens.'), - 'invalid' + _( + "Enter a valid value consisting of lowercase letters, numbers, " + + "underscores or hyphens." + ), + "invalid", ) def can_t_be_other(value): - if value == 'other': + if value == "other": raise ValidationError(_('The label can\'t be named as "other"')) class RepositoryCategory(models.Model): class Meta: - verbose_name = _('repository category') - verbose_name_plural = _('repository categories') + verbose_name = _("repository category") + verbose_name_plural = _("repository categories") - name = models.CharField( - _('name'), - max_length=32) - icon = models.CharField( - _('icon'), - max_length=16, - default='botinho') + name = models.CharField(_("name"), max_length=32) + icon = models.CharField(_("icon"), max_length=16, default="botinho") def __str__(self): return self.name # pragma: no cover @@ -59,23 +56,16 @@ def publics(self): return self.filter(is_private=False) def order_by_relevance(self): - return self \ - .annotate(examples_sum=models.Sum('updates__added')) \ - .order_by('-total_updates', '-examples_sum', '-created_at') + return self.annotate(examples_sum=models.Sum("updates__added")).order_by( + "-total_updates", "-examples_sum", "-created_at" + ) def supported_language(self, language): - valid_examples = RepositoryExample.objects.filter( - deleted_in__isnull=True, - ) - valid_updates = RepositoryUpdate.objects.filter( - added__in=valid_examples, - ) + valid_examples = RepositoryExample.objects.filter(deleted_in__isnull=True) + valid_updates = RepositoryUpdate.objects.filter(added__in=valid_examples) return self.filter( models.Q(language=language) - | models.Q( - updates__in=valid_updates, - updates__language=language, - ) + | models.Q(updates__in=valid_updates, updates__language=language) | models.Q( updates__in=valid_updates, updates__added__translations__language=language, @@ -90,252 +80,242 @@ def get_queryset(self): class Repository(models.Model): class Meta: - verbose_name = _('repository') - verbose_name_plural = _('repositories') - unique_together = ['owner', 'slug'] + verbose_name = _("repository") + verbose_name_plural = _("repositories") + unique_together = ["owner", "slug"] - CATEGORIES_HELP_TEXT = _('Categories for approaching repositories with ' + - 'the same purpose') - DESCRIPTION_HELP_TEXT = _('Tell what your bot do!') + CATEGORIES_HELP_TEXT = _( + "Categories for approaching repositories with " + "the same purpose" + ) + DESCRIPTION_HELP_TEXT = _("Tell what your bot do!") - ALGORITHM_STATISTICAL_MODEL = 'statistical_model' - ALGORITHM_NEURAL_NETWORK_INTERNAL = 'neural_network_internal' - ALGORITHM_NEURAL_NETWORK_EXTERNAL = 'neural_network_external' + ALGORITHM_STATISTICAL_MODEL = "statistical_model" + ALGORITHM_NEURAL_NETWORK_INTERNAL = "neural_network_internal" + ALGORITHM_NEURAL_NETWORK_EXTERNAL = "neural_network_external" ALGORITHM_CHOICES = [ - ( - ALGORITHM_STATISTICAL_MODEL, - _('Statistical Model'), - ), + (ALGORITHM_STATISTICAL_MODEL, _("Statistical Model")), ( ALGORITHM_NEURAL_NETWORK_INTERNAL, - _('Neural Network with internal vocabulary'), + _("Neural Network with internal vocabulary"), ), ( ALGORITHM_NEURAL_NETWORK_EXTERNAL, - _('Neural Network with external vocabulary (BETA)'), + _("Neural Network with external vocabulary (BETA)"), ), ] uuid = models.UUIDField( - _('UUID'), - primary_key=True, - default=uuid.uuid4, - editable=False) - owner = models.ForeignKey( - User, - models.CASCADE, - related_name='repositories') + _("UUID"), primary_key=True, default=uuid.uuid4, editable=False + ) + owner = models.ForeignKey(User, models.CASCADE, related_name="repositories") name = models.CharField( - _('name'), - max_length=64, - help_text=_('Repository display name')) + _("name"), max_length=64, help_text=_("Repository display name") + ) slug = models.SlugField( - _('slug'), + _("slug"), max_length=32, - help_text=_('Easy way to found and share repositories')) + help_text=_("Easy way to found and share repositories"), + ) language = models.CharField( - _('language'), + _("language"), max_length=5, - help_text=_('Repository\'s examples language. The examples can be ' + - 'translated to other languages.'), - validators=[ - languages.validate_language, - ]) + help_text=_( + "Repository's examples language. The examples can be " + + "translated to other languages." + ), + validators=[languages.validate_language], + ) algorithm = models.CharField( - _('algorithm'), + _("algorithm"), max_length=24, choices=ALGORITHM_CHOICES, default=ALGORITHM_STATISTICAL_MODEL, ) use_competing_intents = models.BooleanField( - _('Use competing intents'), - help_text=_('When using competing intents the confidence of the ' + - 'prediction is distributed in all the intents.'), - default=False) + _("Use competing intents"), + help_text=_( + "When using competing intents the confidence of the " + + "prediction is distributed in all the intents." + ), + default=False, + ) use_name_entities = models.BooleanField( - _('Use name entities'), - help_text=_('When enabling name entities you will receive name of ' + - 'people, companies and places as results of your ' + - 'predictions.'), - default=False) + _("Use name entities"), + help_text=_( + "When enabling name entities you will receive name of " + + "people, companies and places as results of your " + + "predictions." + ), + default=False, + ) categories = models.ManyToManyField( - RepositoryCategory, - help_text=CATEGORIES_HELP_TEXT) + RepositoryCategory, help_text=CATEGORIES_HELP_TEXT + ) description = models.TextField( - _('description'), - blank=True, - help_text=DESCRIPTION_HELP_TEXT) + _("description"), blank=True, help_text=DESCRIPTION_HELP_TEXT + ) is_private = models.BooleanField( - _('private'), + _("private"), default=False, - help_text=_('Your repository can be private, only you can see and' + - ' use, or can be public and all community can see and ' + - 'use.')) - created_at = models.DateTimeField( - _('created at'), - auto_now_add=True) + help_text=_( + "Your repository can be private, only you can see and" + + " use, or can be public and all community can see and " + + "use." + ), + ) + created_at = models.DateTimeField(_("created at"), auto_now_add=True) total_updates = models.IntegerField( - _('total updates'), - default=0, - blank=False, - null=False + _("total updates"), default=0, blank=False, null=False ) - nlp_server = models.URLField( - _('Base URL NLP'), - null=True, - blank=True - ) + nlp_server = models.URLField(_("Base URL NLP"), null=True, blank=True) objects = RepositoryManager() def request_nlp_train(self, user_authorization): try: # pragma: no cover r = requests.post( # pragma: no cover - '{}train/'.format( - self.nlp_server if self.nlp_server else - settings.BOTHUB_NLP_BASE_URL + "{}train/".format( + self.nlp_server if self.nlp_server else settings.BOTHUB_NLP_BASE_URL ), data={}, - headers={'Authorization': 'Bearer {}'.format( - user_authorization.uuid)}) + headers={"Authorization": "Bearer {}".format(user_authorization.uuid)}, + ) return r # pragma: no cover except requests.exceptions.ConnectionError: # pragma: no cover raise APIException( # pragma: no cover - {'status_code': status.HTTP_503_SERVICE_UNAVAILABLE}, - code=status.HTTP_503_SERVICE_UNAVAILABLE) + {"status_code": status.HTTP_503_SERVICE_UNAVAILABLE}, + code=status.HTTP_503_SERVICE_UNAVAILABLE, + ) def request_nlp_analyze(self, user_authorization, data): try: # pragma: no cover r = requests.post( # pragma: no cover - '{}parse/'.format( - self.nlp_server if self.nlp_server else - settings.BOTHUB_NLP_BASE_URL + "{}parse/".format( + self.nlp_server if self.nlp_server else settings.BOTHUB_NLP_BASE_URL ), - data={ - 'text': data.get('text'), - 'language': data.get('language'), - }, - headers={'Authorization': 'Bearer {}'.format( - user_authorization.uuid)}) + data={"text": data.get("text"), "language": data.get("language")}, + headers={"Authorization": "Bearer {}".format(user_authorization.uuid)}, + ) return r # pragma: no cover except requests.exceptions.ConnectionError: # pragma: no cover raise APIException( # pragma: no cover - {'status_code': status.HTTP_503_SERVICE_UNAVAILABLE}, - code=status.HTTP_503_SERVICE_UNAVAILABLE) + {"status_code": status.HTTP_503_SERVICE_UNAVAILABLE}, + code=status.HTTP_503_SERVICE_UNAVAILABLE, + ) def request_nlp_evaluate(self, user_authorization, data): try: # pragma: no cover r = requests.post( # pragma: no cover - '{}evaluate/'.format( - self.nlp_server if self.nlp_server else - settings.BOTHUB_NLP_BASE_URL + "{}evaluate/".format( + self.nlp_server if self.nlp_server else settings.BOTHUB_NLP_BASE_URL ), - data={ - 'language': data.get('language'), - }, - headers={'Authorization': 'Bearer {}'.format( - user_authorization.uuid)}) + data={"language": data.get("language")}, + headers={"Authorization": "Bearer {}".format(user_authorization.uuid)}, + ) return r # pragma: no cover except requests.exceptions.ConnectionError: # pragma: no cover raise APIException( # pragma: no cover - {'status_code': status.HTTP_503_SERVICE_UNAVAILABLE}, - code=status.HTTP_503_SERVICE_UNAVAILABLE) + {"status_code": status.HTTP_503_SERVICE_UNAVAILABLE}, + code=status.HTTP_503_SERVICE_UNAVAILABLE, + ) @property def available_languages(self): examples = self.examples() examples_languages = examples.values_list( - 'repository_update__language', - flat=True) - translations_languages = examples.annotate( - translations_count=models.Count('translations')).filter( - translations_count__gt=0).values_list( - 'translations__language', - flat=True) - return list(set( - [self.language] + - list(examples_languages) + - list(translations_languages))) + "repository_update__language", flat=True + ) + translations_languages = ( + examples.annotate(translations_count=models.Count("translations")) + .filter(translations_count__gt=0) + .values_list("translations__language", flat=True) + ) + return list( + set( + [self.language] + + list(examples_languages) + + list(translations_languages) + ) + ) @property def languages_status(self): return dict( map( - lambda language: ( - language, - self.language_status(language)), + lambda language: (language, self.language_status(language)), settings.SUPPORTED_LANGUAGES.keys(), - )) + ) + ) @property def current_updates(self): - return map( - lambda lang: self.current_update(lang), - self.available_languages) + return map(lambda lang: self.current_update(lang), self.available_languages) @property def requirements_to_train(self): - return dict(filter( - lambda l: l[1], - map( - lambda u: (u.language, u.requirements_to_train,), - self.current_updates))) + return dict( + filter( + lambda l: l[1], + map( + lambda u: (u.language, u.requirements_to_train), + self.current_updates, + ), + ) + ) @property def languages_ready_for_train(self): - return dict(map( - lambda u: (u.language, u.ready_for_train,), - self.current_updates)) + return dict( + map(lambda u: (u.language, u.ready_for_train), self.current_updates) + ) @property def ready_for_train(self): return reduce( - lambda current, u: u.ready_for_train or current, - self.current_updates, - False) + lambda current, u: u.ready_for_train or current, self.current_updates, False + ) @property def languages_warnings(self): - return dict(filter( + return dict( + filter( lambda w: len(w[1]) > 0, - map( - lambda u: (u.language, u.warnings,), - self.current_updates))) + map(lambda u: (u.language, u.warnings), self.current_updates), + ) + ) @property def intents(self): - return list(set(self.examples( - exclude_deleted=True).exclude( - intent='').values_list( - 'intent', - flat=True))) + return list( + set( + self.examples(exclude_deleted=True) + .exclude(intent="") + .values_list("intent", flat=True) + ) + ) @property def current_entities(self): - return self.entities.filter(value__in=self.examples( - exclude_deleted=True).exclude( - entities__entity__value__isnull=True).values_list( - 'entities__entity__value', - flat=True).distinct()) + return self.entities.filter( + value__in=self.examples(exclude_deleted=True) + .exclude(entities__entity__value__isnull=True) + .values_list("entities__entity__value", flat=True) + .distinct() + ) @property def entities_list(self): - return self.current_entities.values_list( - 'value', - flat=True).distinct() + return self.current_entities.values_list("value", flat=True).distinct() @property def current_labels(self): - return self.labels.filter( - entities__value__in=self.entities_list).distinct() + return self.labels.filter(entities__value__in=self.entities_list).distinct() @property def labels_list(self): - return self.current_labels.values_list( - 'value', - flat=True).distinct() + return self.current_labels.values_list("value", flat=True).distinct() @property def other_entities(self): @@ -344,8 +324,10 @@ def other_entities(self): @property def admins(self): admins = [self.owner] + [ - authorization.user for authorization in - self.authorizations.filter(role=RepositoryAuthorization.ROLE_ADMIN) + authorization.user + for authorization in self.authorizations.filter( + role=RepositoryAuthorization.ROLE_ADMIN + ) ] return list(set(admins)) @@ -354,20 +336,16 @@ def use_language_model_featurizer(self): return self.algorithm != Repository.ALGORITHM_NEURAL_NETWORK_INTERNAL def __str__(self): - return 'Repository {} - {}/{}'.format( - self.name, - self.owner.nickname, - self.slug, + return "Repository {} - {}/{}".format( + self.name, self.owner.nickname, self.slug ) # pragma: no cover def examples(self, language=None, exclude_deleted=True, queryset=None): if queryset is None: queryset = RepositoryExample.objects - query = queryset.filter( - repository_update__repository=self) + query = queryset.filter(repository_update__repository=self) if language: - query = query.filter( - repository_update__language=language) + query = query.filter(repository_update__language=language) if exclude_deleted: return query.exclude(deleted_in__isnull=False) return query @@ -375,11 +353,9 @@ def examples(self, language=None, exclude_deleted=True, queryset=None): def evaluations(self, language=None, exclude_deleted=True, queryset=None): if queryset is None: queryset = RepositoryEvaluate.objects - query = queryset.filter( - repository_update__repository=self) + query = queryset.filter(repository_update__repository=self) if language: - query = query.filter( - repository_update__language=language) + query = query.filter(repository_update__language=language) if exclude_deleted: return query.exclude(deleted_in__isnull=False) return query # pragma: no cover @@ -387,8 +363,7 @@ def evaluations(self, language=None, exclude_deleted=True, queryset=None): def evaluations_results(self, queryset=None): if queryset is None: queryset = RepositoryEvaluateResult.objects - query = queryset.filter( - repository_update__repository=self) + query = queryset.filter(repository_update__repository=self) return query def language_status(self, language): @@ -396,130 +371,110 @@ def language_status(self, language): examples = self.examples(language) base_examples = self.examples(self.language) base_translations = RepositoryTranslatedExample.objects.filter( - original_example__in=base_examples, - language=language) + original_example__in=base_examples, language=language + ) examples_count = examples.count() base_examples_count = base_examples.count() base_translations_count = base_translations.count() base_translations_percentage = ( - base_translations_count / ( - base_examples_count if base_examples_count > 0 else 1)) * 100 + base_translations_count + / (base_examples_count if base_examples_count > 0 else 1) + ) * 100 return { - 'is_base_language': is_base_language, - 'examples': { - 'count': examples_count, - 'entities': list( + "is_base_language": is_base_language, + "examples": { + "count": examples_count, + "entities": list( set( filter( lambda x: x, examples.values_list( - 'entities__entity', - flat=True).distinct()))), + "entities__entity", flat=True + ).distinct(), + ) + ) + ), }, - 'base_translations': { - 'count': base_translations_count, - 'percentage': base_translations_percentage, + "base_translations": { + "count": base_translations_count, + "percentage": base_translations_percentage, }, } def current_update(self, language=None): language = language or self.language repository_update, created = self.updates.get_or_create( - language=language, - training_started_at=None) + language=language, training_started_at=None + ) return repository_update def last_trained_update(self, language=None): language = language or self.language return self.updates.filter( - language=language, - by__isnull=False, - trained_at__isnull=False).first() + language=language, by__isnull=False, trained_at__isnull=False + ).first() def get_user_authorization(self, user): if user.is_anonymous: return RepositoryAuthorization(repository=self) get, created = RepositoryAuthorization.objects.get_or_create( - user=user, - repository=self) + user=user, repository=self + ) return get def get_absolute_url(self): - return '{}{}/{}/'.format( - settings.BOTHUB_WEBAPP_BASE_URL, - self.owner.nickname, - self.slug) + return "{}{}/{}/".format( + settings.BOTHUB_WEBAPP_BASE_URL, self.owner.nickname, self.slug + ) class RepositoryUpdate(models.Model): class Meta: - verbose_name = _('repository update') - verbose_name_plural = _('repository updates') - ordering = ['-created_at'] + verbose_name = _("repository update") + verbose_name_plural = _("repository updates") + ordering = ["-created_at"] MIN_EXAMPLES_PER_INTENT = 2 MIN_EXAMPLES_PER_ENTITY = 2 RECOMMENDED_INTENTS = 2 - repository = models.ForeignKey( - Repository, - models.CASCADE, - related_name='updates') + repository = models.ForeignKey(Repository, models.CASCADE, related_name="updates") language = models.CharField( - _('language'), - max_length=5, - validators=[ - languages.validate_language, - ]) + _("language"), max_length=5, validators=[languages.validate_language] + ) algorithm = models.CharField( - _('algorithm'), + _("algorithm"), max_length=24, choices=Repository.ALGORITHM_CHOICES, default=Repository.ALGORITHM_STATISTICAL_MODEL, ) use_competing_intents = models.BooleanField(default=False) use_name_entities = models.BooleanField(default=False) - created_at = models.DateTimeField( - _('created at'), - auto_now_add=True) - bot_data = models.URLField( - _('bot data'), - blank=True) - by = models.ForeignKey( - User, - models.CASCADE, - blank=True, - null=True) + created_at = models.DateTimeField(_("created at"), auto_now_add=True) + bot_data = models.URLField(_("bot data"), blank=True) + by = models.ForeignKey(User, models.CASCADE, blank=True, null=True) training_started_at = models.DateTimeField( - _('training started at'), - blank=True, - null=True) - trained_at = models.DateTimeField( - _('trained at'), - blank=True, - null=True) - failed_at = models.DateTimeField( - _('failed at'), - blank=True, - null=True) - training_log = models.TextField( - _('training log'), - blank=True, - editable=False) + _("training started at"), blank=True, null=True + ) + trained_at = models.DateTimeField(_("trained at"), blank=True, null=True) + failed_at = models.DateTimeField(_("failed at"), blank=True, null=True) + training_log = models.TextField(_("training log"), blank=True, editable=False) @property def examples(self): examples = self.repository.examples(exclude_deleted=False).filter( - models.Q(repository_update__language=self.language) | - models.Q(translations__language=self.language)) + models.Q(repository_update__language=self.language) + | models.Q(translations__language=self.language) + ) if self.training_started_at: t_started_at = self.training_started_at examples = examples.exclude( - models.Q(repository_update__created_at__gt=t_started_at) | - models.Q(deleted_in=self) | - models.Q(deleted_in__training_started_at__lt=t_started_at)) + models.Q(repository_update__created_at__gt=t_started_at) + | models.Q(deleted_in=self) + | models.Q(deleted_in__training_started_at__lt=t_started_at) + ) else: examples = examples.exclude(deleted_in__isnull=False) return examples @@ -529,41 +484,50 @@ def requirements_to_train(self): try: self.validate_init_train() except RepositoryUpdateAlreadyTrained: # pragma: no cover - return [_('This bot version has already been trained.')] + return [_("This bot version has already been trained.")] except RepositoryUpdateAlreadyStartedTraining: # pragma: no cover - return [_('This bot version is being trained.')] + return [_("This bot version is being trained.")] r = [] - intents = self.examples.values_list('intent', flat=True) + intents = self.examples.values_list("intent", flat=True) - if '' in intents: - r.append(_('All examples need have a intent.')) + if "" in intents: + r.append(_("All examples need have a intent.")) - weak_intents = self.examples.values('intent').annotate( - intent_count=models.Count('id')).order_by().exclude( - intent_count__gte=self.MIN_EXAMPLES_PER_INTENT) + weak_intents = ( + self.examples.values("intent") + .annotate(intent_count=models.Count("id")) + .order_by() + .exclude(intent_count__gte=self.MIN_EXAMPLES_PER_INTENT) + ) if weak_intents.exists(): for i in weak_intents: - r.append(_('Intent "{}" has only {} examples. ' + - 'Minimum is {}.').format( - i.get('intent'), - i.get('intent_count'), - self.MIN_EXAMPLES_PER_INTENT)) - - weak_entities = self.examples.annotate( - es_count=models.Count('entities')).filter( - es_count__gte=1).values( - 'entities__entity__value').annotate( - entities_count=models.Count('id')).order_by().exclude( - entities_count__gte=self.MIN_EXAMPLES_PER_ENTITY) + r.append( + _('Intent "{}" has only {} examples. ' + "Minimum is {}.").format( + i.get("intent"), + i.get("intent_count"), + self.MIN_EXAMPLES_PER_INTENT, + ) + ) + + weak_entities = ( + self.examples.annotate(es_count=models.Count("entities")) + .filter(es_count__gte=1) + .values("entities__entity__value") + .annotate(entities_count=models.Count("id")) + .order_by() + .exclude(entities_count__gte=self.MIN_EXAMPLES_PER_ENTITY) + ) if weak_entities.exists(): for e in weak_entities: - r.append(_('Entity "{}" has only {} examples. ' + - 'Minimum is {}.').format( - e.get('entities__entity__value'), - e.get('entities_count'), - self.MIN_EXAMPLES_PER_ENTITY)) + r.append( + _('Entity "{}" has only {} examples. ' + "Minimum is {}.").format( + e.get("entities__entity__value"), + e.get("entities_count"), + self.MIN_EXAMPLES_PER_ENTITY, + ) + ) return r @@ -579,23 +543,30 @@ def ready_for_train(self): language=self.language, by__isnull=False, training_started_at__isnull=False, - created_at__lt=self.created_at).first() + created_at__lt=self.created_at, + ).first() if previous_update: if previous_update.algorithm != self.repository.algorithm: return True - if previous_update.use_competing_intents is not \ - self.repository.use_competing_intents: + if ( + previous_update.use_competing_intents + is not self.repository.use_competing_intents + ): return True - if previous_update.use_name_entities is not \ - self.repository.use_name_entities: + if ( + previous_update.use_name_entities + is not self.repository.use_name_entities + ): return True if previous_update.failed_at: return True - if not self.added.exists() and \ - not self.translated_added.exists() and \ - not self.deleted.exists(): + if ( + not self.added.exists() + and not self.translated_added.exists() + and not self.deleted.exists() + ): return False if self.examples.count() == 0: @@ -605,15 +576,18 @@ def ready_for_train(self): @property def intents(self): - return list(set(self.examples.values_list('intent', flat=True))) + return list(set(self.examples.values_list("intent", flat=True))) @property def warnings(self): w = [] if 0 < len(self.intents) < self.RECOMMENDED_INTENTS: - w.append(_('You need to have at least {} intents for the ' + - 'algorithm to identify intents.').format( - self.RECOMMENDED_INTENTS)) + w.append( + _( + "You need to have at least {} intents for the " + + "algorithm to identify intents." + ).format(self.RECOMMENDED_INTENTS) + ) return w @property @@ -621,7 +595,7 @@ def use_language_model_featurizer(self): return self.algorithm != Repository.ALGORITHM_NEURAL_NETWORK_INTERNAL def __str__(self): - return 'Repository Update #{}'.format(self.id) # pragma: no cover + return "Repository Update #{}".format(self.id) # pragma: no cover def validate_init_train(self, by=None): if self.trained_at: @@ -642,12 +616,13 @@ def start_training(self, by): self.use_name_entities = self.repository.use_name_entities self.save( update_fields=[ - 'by', - 'training_started_at', - 'algorithm', - 'use_competing_intents', - 'use_name_entities', - ]) + "by", + "training_started_at", + "algorithm", + "use_competing_intents", + "use_name_entities", + ] + ) def save_training(self, bot_data): if self.trained_at: @@ -657,52 +632,37 @@ def save_training(self, bot_data): self.bot_data = bot_data self.repository.total_updates += 1 self.repository.save() - self.save( - update_fields=[ - 'trained_at', - 'bot_data', - ]) + self.save(update_fields=["trained_at", "bot_data"]) def get_bot_data(self): return self.bot_data def train_fail(self): self.failed_at = timezone.now() - self.save( - update_fields=[ - 'failed_at', - ]) + self.save(update_fields=["failed_at"]) class RepositoryExample(models.Model): class Meta: - verbose_name = _('repository example') - verbose_name_plural = _('repository examples') - ordering = ['-created_at'] + verbose_name = _("repository example") + verbose_name_plural = _("repository examples") + ordering = ["-created_at"] repository_update = models.ForeignKey( - RepositoryUpdate, - models.CASCADE, - related_name='added', - editable=False) + RepositoryUpdate, models.CASCADE, related_name="added", editable=False + ) deleted_in = models.ForeignKey( - RepositoryUpdate, - models.CASCADE, - related_name='deleted', - blank=True, - null=True) - text = models.TextField( - _('text'), - help_text=_('Example text')) + RepositoryUpdate, models.CASCADE, related_name="deleted", blank=True, null=True + ) + text = models.TextField(_("text"), help_text=_("Example text")) intent = models.CharField( - _('intent'), + _("intent"), max_length=64, - default='no_intent', - help_text=_('Example intent reference'), - validators=[validate_item_key]) - created_at = models.DateTimeField( - _('created at'), - auto_now_add=True) + default="no_intent", + help_text=_("Example intent reference"), + validators=[validate_item_key], + ) + created_at = models.DateTimeField(_("created at"), auto_now_add=True) @property def language(self): @@ -731,8 +691,9 @@ def get_entities(self, language): # pragma: no cover def delete(self): self.deleted_in = self.repository_update.repository.current_update( - self.repository_update.language) - self.save(update_fields=['deleted_in']) + self.repository_update.language + ) + self.save(update_fields=["deleted_in"]) class RepositoryTranslatedExampleManager(models.Manager): @@ -743,59 +704,53 @@ def create(self, *args, original_example=None, language=None, **kwargs): repository_update=repository.current_update(language), original_example=original_example, language=language, - **kwargs) + **kwargs + ) class RepositoryTranslatedExample(models.Model): class Meta: - verbose_name = _('repository translated example') - verbose_name_plural = _('repository translated examples') - unique_together = ['original_example', 'language'] - ordering = ['-created_at'] + verbose_name = _("repository translated example") + verbose_name_plural = _("repository translated examples") + unique_together = ["original_example", "language"] + ordering = ["-created_at"] repository_update = models.ForeignKey( RepositoryUpdate, models.CASCADE, - related_name='translated_added', - editable=False) + related_name="translated_added", + editable=False, + ) original_example = models.ForeignKey( RepositoryExample, models.CASCADE, - related_name='translations', + related_name="translations", editable=False, - help_text=_('Example object')) + help_text=_("Example object"), + ) language = models.CharField( - _('language'), + _("language"), max_length=5, - help_text=_('Translation language'), - validators=[ - languages.validate_language, - ]) - text = models.TextField( - _('text'), - help_text=_('Translation text')) - created_at = models.DateTimeField( - _('created at'), - auto_now_add=True) + help_text=_("Translation language"), + validators=[languages.validate_language], + ) + text = models.TextField(_("text"), help_text=_("Translation text")) + created_at = models.DateTimeField(_("created at"), auto_now_add=True) objects = RepositoryTranslatedExampleManager() def entities_list_lambda_sort(item): - return item.get('entity') + return item.get("entity") @classmethod def same_entities_validator(cls, a, b): a_len = len(a) if a_len != len(b): return False - a_sorted = sorted( - a, - key=cls.entities_list_lambda_sort) - b_sorted = sorted( - b, - key=cls.entities_list_lambda_sort) + a_sorted = sorted(a, key=cls.entities_list_lambda_sort) + b_sorted = sorted(b, key=cls.entities_list_lambda_sort) for i in range(a_len): - if a_sorted[i].get('entity') != b_sorted[i].get('entity'): + if a_sorted[i].get("entity") != b_sorted[i].get("entity"): return False return True @@ -803,11 +758,13 @@ def same_entities_validator(cls, a, b): def count_entities(cls, entities_list, to_str=False): r = {} for e in entities_list: - r.update({e.get('entity'): r.get('entity', 0) + 1}) + r.update({e.get("entity"): r.get("entity", 0) + 1}) if to_str: - r = ', '.join(map( - lambda x: '{} {}'.format(x[1], x[0]), - r.items())) if entities_list else 'no entities' + r = ( + ", ".join(map(lambda x: "{} {}".format(x[1], x[0]), r.items())) + if entities_list + else "no entities" + ) return r @property @@ -816,19 +773,16 @@ def has_valid_entities(self): my_entities = self.entities.all() return RepositoryTranslatedExample.same_entities_validator( list(map(lambda x: x.to_dict, original_entities)), - list(map(lambda x: x.to_dict, my_entities))) + list(map(lambda x: x.to_dict, my_entities)), + ) class RepositoryEntityLabelQueryset(models.QuerySet): def get(self, repository, value): try: - return super().get( - repository=repository, - value=value) + return super().get(repository=repository, value=value) except self.model.DoesNotExist: - return super().create( - repository=repository, - value=value) + return super().create(repository=repository, value=value) class RepositoryEntityLabelManager(models.Manager): @@ -838,45 +792,36 @@ def get_queryset(self): class RepositoryEntityLabel(models.Model): class Meta: - unique_together = ['repository', 'value'] + unique_together = ["repository", "value"] repository = models.ForeignKey( - Repository, - on_delete=models.CASCADE, - related_name='labels') + Repository, on_delete=models.CASCADE, related_name="labels" + ) value = models.CharField( - _('label'), + _("label"), max_length=64, - validators=[ - validate_item_key, - can_t_be_other, - ], - blank=True) - created_at = models.DateTimeField( - _('created at'), - auto_now_add=True) + validators=[validate_item_key, can_t_be_other], + blank=True, + ) + created_at = models.DateTimeField(_("created at"), auto_now_add=True) objects = RepositoryEntityLabelManager() def examples(self, exclude_deleted=True): # pragma: no cover - return self.repository.examples( - exclude_deleted=exclude_deleted).filter( - entities__entity__label=self) + return self.repository.examples(exclude_deleted=exclude_deleted).filter( + entities__entity__label=self + ) class RepositoryEntityQueryset(models.QuerySet): def get(self, repository, value, create_entity=True): try: - return super().get( - repository=repository, - value=value) + return super().get(repository=repository, value=value) except self.model.DoesNotExist: if not create_entity: raise self.model.DoesNotExist # pragma: no cover - return super().create( - repository=repository, - value=value) + return super().create(repository=repository, value=value) class RepositoryEntityManager(models.Manager): @@ -886,26 +831,25 @@ def get_queryset(self): class RepositoryEntity(models.Model): class Meta: - unique_together = ['repository', 'value'] + unique_together = ["repository", "value"] repository = models.ForeignKey( - Repository, - on_delete=models.CASCADE, - related_name='entities') + Repository, on_delete=models.CASCADE, related_name="entities" + ) value = models.CharField( - _('entity'), + _("entity"), max_length=64, - help_text=_('Entity name'), - validators=[validate_item_key]) + help_text=_("Entity name"), + validators=[validate_item_key], + ) label = models.ForeignKey( RepositoryEntityLabel, on_delete=models.CASCADE, - related_name='entities', + related_name="entities", null=True, - blank=True) - created_at = models.DateTimeField( - _('created at'), - auto_now_add=True) + blank=True, + ) + created_at = models.DateTimeField(_("created at"), auto_now_add=True) objects = RepositoryEntityManager() @@ -914,30 +858,26 @@ def set_label(self, value): self.label = None else: self.label = RepositoryEntityLabel.objects.get( - repository=self.repository, - value=value) + repository=self.repository, value=value + ) class EntityBaseQueryset(models.QuerySet): # pragma: no cover def create(self, entity, **kwargs): if type(entity) is not RepositoryEntity: instance = self.model(**kwargs) - if 'repository_evaluate_id' in instance.__dict__: + if "repository_evaluate_id" in instance.__dict__: evaluate = instance.repository_evaluate repository = evaluate.repository_update.repository - elif 'evaluate_result_id' in instance.__dict__: + elif "evaluate_result_id" in instance.__dict__: result = instance.evaluate_result repository = result.repository_update.repository else: repository = instance.example.repository_update.repository - entity = RepositoryEntity.objects.get( - repository=repository, - value=entity) + entity = RepositoryEntity.objects.get(repository=repository, value=entity) - return super().create( - entity=entity, - **kwargs) + return super().create(entity=entity, **kwargs) class EntityBaseManager(models.Manager): @@ -947,22 +887,18 @@ def get_queryset(self): class EntityBase(models.Model): class Meta: - verbose_name = _('repository example entity') - verbose_name_plural = _('repository example entities') + verbose_name = _("repository example entity") + verbose_name_plural = _("repository example entities") abstract = True start = models.PositiveIntegerField( - _('start'), - help_text=_('Start index of entity value in example text')) + _("start"), help_text=_("Start index of entity value in example text") + ) end = models.PositiveIntegerField( - _('end'), - help_text=_('End index of entity value in example text')) - entity = models.ForeignKey( - RepositoryEntity, - on_delete=models.CASCADE) - created_at = models.DateTimeField( - _('created at'), - auto_now_add=True) + _("end"), help_text=_("End index of entity value in example text") + ) + entity = models.ForeignKey(RepositoryEntity, on_delete=models.CASCADE) + created_at = models.DateTimeField(_("created at"), auto_now_add=True) objects = EntityBaseManager() @@ -972,15 +908,15 @@ def example(self): @property def value(self): - return self.example.text[self.start:self.end] + return self.example.text[self.start : self.end] @property def rasa_nlu_data(self): # pragma: no cover return { - 'start': self.start, - 'end': self.end, - 'value': self.value, - 'entity': self.entity.value, + "start": self.start, + "end": self.end, + "value": self.value, + "entity": self.entity.value, } @property @@ -992,10 +928,9 @@ def get_example(self): def get_rasa_nlu_data(self, label_as_entity=False): return { - 'start': self.start, - 'end': self.end, - 'entity': self.entity.label.value - if label_as_entity else self.entity.value, + "start": self.start, + "end": self.end, + "entity": self.entity.label.value if label_as_entity else self.entity.value, } @@ -1003,9 +938,10 @@ class RepositoryExampleEntity(EntityBase): repository_example = models.ForeignKey( RepositoryExample, models.CASCADE, - related_name='entities', + related_name="entities", editable=False, - help_text=_('Example object')) + help_text=_("Example object"), + ) def get_example(self): return self.repository_example @@ -1015,9 +951,10 @@ class RepositoryTranslatedExampleEntity(EntityBase): repository_translated_example = models.ForeignKey( RepositoryTranslatedExample, models.CASCADE, - related_name='entities', + related_name="entities", editable=False, - help_text=_('Translated example object')) + help_text=_("Translated example object"), + ) def get_example(self): return self.repository_translated_example @@ -1025,9 +962,9 @@ def get_example(self): class RepositoryAuthorization(models.Model): class Meta: - verbose_name = _('repository authorization') - verbose_name_plural = _('repository authorizations') - unique_together = ['user', 'repository'] + verbose_name = _("repository authorization") + verbose_name_plural = _("repository authorizations") + unique_together = ["user", "repository"] LEVEL_NOTHING = 0 LEVEL_READER = 1 @@ -1040,31 +977,23 @@ class Meta: ROLE_ADMIN = 3 ROLE_CHOICES = [ - (ROLE_NOT_SETTED, _('not set')), - (ROLE_USER, _('user')), - (ROLE_CONTRIBUTOR, _('contributor')), - (ROLE_ADMIN, _('admin')), + (ROLE_NOT_SETTED, _("not set")), + (ROLE_USER, _("user")), + (ROLE_CONTRIBUTOR, _("contributor")), + (ROLE_ADMIN, _("admin")), ] uuid = models.UUIDField( - _('UUID'), - primary_key=True, - default=uuid.uuid4, - editable=False) - user = models.ForeignKey( - User, - models.CASCADE) + _("UUID"), primary_key=True, default=uuid.uuid4, editable=False + ) + user = models.ForeignKey(User, models.CASCADE) repository = models.ForeignKey( - Repository, - models.CASCADE, - related_name='authorizations') + Repository, models.CASCADE, related_name="authorizations" + ) role = models.PositiveIntegerField( - _('role'), - choices=ROLE_CHOICES, - default=ROLE_NOT_SETTED) - created_at = models.DateTimeField( - _('created at'), - auto_now_add=True) + _("role"), choices=ROLE_CHOICES, default=ROLE_NOT_SETTED + ) + created_at = models.DateTimeField(_("created at"), auto_now_add=True) @property def level(self): @@ -1109,9 +1038,7 @@ def can_contribute(self): @property def can_write(self): - return self.level in [ - RepositoryAuthorization.LEVEL_ADMIN, - ] + return self.level in [RepositoryAuthorization.LEVEL_ADMIN] @property def is_admin(self): @@ -1132,165 +1059,126 @@ def role_verbose(self): def send_new_role_email(self, responsible=None): if not settings.SEND_EMAILS: return False # pragma: no cover - responsible_name = responsible and responsible.name \ - or self.repository.owner.name + responsible_name = ( + responsible and responsible.name or self.repository.owner.name + ) context = { - 'responsible_name': responsible_name, - 'user_name': self.user.name, - 'repository_name': self.repository.name, - 'repository_url': self.repository.get_absolute_url(), - 'new_role': self.role_verbose, + "responsible_name": responsible_name, + "user_name": self.user.name, + "repository_name": self.repository.name, + "repository_url": self.repository.get_absolute_url(), + "new_role": self.role_verbose, } send_mail( - _('New role in {}').format(self.repository.name), - render_to_string( - 'common/emails/new_role.txt', - context), + _("New role in {}").format(self.repository.name), + render_to_string("common/emails/new_role.txt", context), None, [self.user.email], - html_message=render_to_string( - 'common/emails/new_role.html', - context)) + html_message=render_to_string("common/emails/new_role.html", context), + ) class RepositoryVote(models.Model): class Meta: - verbose_name = _('repository vote') - verbose_name_plural = _('repository votes') - unique_together = [ - 'user', - 'repository', - ] + verbose_name = _("repository vote") + verbose_name_plural = _("repository votes") + unique_together = ["user", "repository"] - user = models.ForeignKey( - User, - models.CASCADE, - related_name='repository_votes') - repository = models.ForeignKey( - Repository, - models.CASCADE, - related_name='votes') - created = models.DateTimeField( - editable=False, - auto_now_add=True - ) + user = models.ForeignKey(User, models.CASCADE, related_name="repository_votes") + repository = models.ForeignKey(Repository, models.CASCADE, related_name="votes") + created = models.DateTimeField(editable=False, auto_now_add=True) class RequestRepositoryAuthorization(models.Model): class Meta: - unique_together = ['user', 'repository'] + unique_together = ["user", "repository"] - user = models.ForeignKey( - User, - models.CASCADE, - related_name='requests') - repository = models.ForeignKey( - Repository, - models.CASCADE, - related_name='requests') - text = models.CharField( - _('text'), - max_length=250) - approved_by = models.ForeignKey( - User, - models.CASCADE, - blank=True, - null=True) + user = models.ForeignKey(User, models.CASCADE, related_name="requests") + repository = models.ForeignKey(Repository, models.CASCADE, related_name="requests") + text = models.CharField(_("text"), max_length=250) + approved_by = models.ForeignKey(User, models.CASCADE, blank=True, null=True) created_at = models.DateTimeField( - _('created at'), - auto_now_add=True, - editable=False) + _("created at"), auto_now_add=True, editable=False + ) def send_new_request_email_to_admins(self): if not settings.SEND_EMAILS: return False # pragma: no cover context = { - 'user_name': self.user.name, - 'repository_name': self.repository.name, - 'text': self.text, - 'repository_url': self.repository.get_absolute_url(), + "user_name": self.user.name, + "repository_name": self.repository.name, + "text": self.text, + "repository_url": self.repository.get_absolute_url(), } for admin in self.repository.admins: send_mail( - _('New authorization request in {}').format( - self.repository.name), - render_to_string( - 'common/emails/new_request.txt', - context), + _("New authorization request in {}").format(self.repository.name), + render_to_string("common/emails/new_request.txt", context), None, [admin.email], html_message=render_to_string( - 'common/emails/new_request.html', - context)) + "common/emails/new_request.html", context + ), + ) def send_request_rejected_email(self): if not settings.SEND_EMAILS: return False # pragma: no cover - context = { - 'repository_name': self.repository.name, - } + context = {"repository_name": self.repository.name} send_mail( - _('Access denied to {}').format( - self.repository.name), - render_to_string( - 'common/emails/request_rejected.txt', - context), + _("Access denied to {}").format(self.repository.name), + render_to_string("common/emails/request_rejected.txt", context), None, [self.user.email], html_message=render_to_string( - 'common/emails/request_rejected.html', - context)) + "common/emails/request_rejected.html", context + ), + ) def send_request_approved_email(self): if not settings.SEND_EMAILS: return False # pragma: no cover context = { - 'admin_name': self.approved_by.name, - 'repository_name': self.repository.name, + "admin_name": self.approved_by.name, + "repository_name": self.repository.name, } send_mail( - _('Authorization Request Approved to {}').format( - self.repository.name), - render_to_string( - 'common/emails/request_approved.txt', - context), + _("Authorization Request Approved to {}").format(self.repository.name), + render_to_string("common/emails/request_approved.txt", context), None, [self.user.email], html_message=render_to_string( - 'common/emails/request_approved.html', - context)) + "common/emails/request_approved.html", context + ), + ) class RepositoryEvaluate(models.Model): class Meta: - verbose_name = _('repository evaluate test') - verbose_name_plural = _('repository evaluate tests') - ordering = ['-created_at'] - db_table = 'common_repository_evaluate' + verbose_name = _("repository evaluate test") + verbose_name_plural = _("repository evaluate tests") + ordering = ["-created_at"] + db_table = "common_repository_evaluate" repository_update = models.ForeignKey( - RepositoryUpdate, - models.CASCADE, - related_name='added_evaluate', - editable=False) + RepositoryUpdate, models.CASCADE, related_name="added_evaluate", editable=False + ) deleted_in = models.ForeignKey( RepositoryUpdate, models.CASCADE, - related_name='deleted_evaluate', + related_name="deleted_evaluate", blank=True, - null=True) - text = models.TextField( - _('text'), - help_text=_('Evaluate test text')) + null=True, + ) + text = models.TextField(_("text"), help_text=_("Evaluate test text")) intent = models.CharField( - _('intent'), + _("intent"), max_length=64, - default='no_intent', - help_text=_('Evaluate intent reference'), - validators=[validate_item_key]) - created_at = models.DateTimeField( - _('created at'), - auto_now_add=True) + default="no_intent", + help_text=_("Evaluate intent reference"), + validators=[validate_item_key], + ) + created_at = models.DateTimeField(_("created at"), auto_now_add=True) @property def language(self): @@ -1308,8 +1196,9 @@ def get_entities(self, language): # pragma: no cover def delete(self): self.deleted_in = self.repository_update.repository.current_update( - self.repository_update.language) - self.save(update_fields=['deleted_in']) + self.repository_update.language + ) + self.save(update_fields=["deleted_in"]) def delete_entities(self): self.entities.all().delete() @@ -1317,14 +1206,15 @@ def delete_entities(self): class RepositoryEvaluateEntity(EntityBase): class Meta: - db_table = 'common_repository_evaluate_entity' + db_table = "common_repository_evaluate_entity" repository_evaluate = models.ForeignKey( RepositoryEvaluate, models.CASCADE, - related_name='entities', + related_name="entities", editable=False, - help_text=_('evaluate object')) + help_text=_("evaluate object"), + ) def get_evaluate(self): # pragma: no cover return self.repository_evaluate @@ -1332,84 +1222,62 @@ def get_evaluate(self): # pragma: no cover class RepositoryEvaluateResultScore(models.Model): class Meta: - db_table = 'common_repository_evaluate_result_score' - ordering = ['-created_at'] + db_table = "common_repository_evaluate_result_score" + ordering = ["-created_at"] - precision = models.DecimalField( - max_digits=3, - decimal_places=2, - null=True) + precision = models.DecimalField(max_digits=3, decimal_places=2, null=True) - f1_score = models.DecimalField( - max_digits=3, - decimal_places=2, - null=True) + f1_score = models.DecimalField(max_digits=3, decimal_places=2, null=True) - accuracy = models.DecimalField( - max_digits=3, - decimal_places=2, - null=True) + accuracy = models.DecimalField(max_digits=3, decimal_places=2, null=True) - recall = models.DecimalField( - max_digits=3, - decimal_places=2, - null=True) + recall = models.DecimalField(max_digits=3, decimal_places=2, null=True) - support = models.IntegerField( - null=True) + support = models.IntegerField(null=True) - created_at = models.DateTimeField( - _('created at'), - auto_now_add=True) + created_at = models.DateTimeField(_("created at"), auto_now_add=True) class RepositoryEvaluateResult(models.Model): class Meta: - db_table = 'common_repository_evaluate_result' - verbose_name = _('evaluate results') - verbose_name_plural = _('evaluate results') - ordering = ['-created_at'] + db_table = "common_repository_evaluate_result" + verbose_name = _("evaluate results") + verbose_name_plural = _("evaluate results") + ordering = ["-created_at"] repository_update = models.ForeignKey( - RepositoryUpdate, - models.CASCADE, - editable=False, - related_name='results') + RepositoryUpdate, models.CASCADE, editable=False, related_name="results" + ) intent_results = models.ForeignKey( RepositoryEvaluateResultScore, models.CASCADE, editable=False, - related_name='intent_results') + related_name="intent_results", + ) entity_results = models.ForeignKey( RepositoryEvaluateResultScore, models.CASCADE, editable=False, - related_name='entity_results') + related_name="entity_results", + ) matrix_chart = models.URLField( - verbose_name=_('Intent Confusion Matrix Chart'), - editable=False) + verbose_name=_("Intent Confusion Matrix Chart"), editable=False + ) confidence_chart = models.URLField( - verbose_name=_('Intent Prediction Confidence Distribution'), - editable=False) + verbose_name=_("Intent Prediction Confidence Distribution"), editable=False + ) - log = models.TextField( - verbose_name=_('Evaluate Log'), - blank=True, - editable=False) + log = models.TextField(verbose_name=_("Evaluate Log"), blank=True, editable=False) version = models.IntegerField( - verbose_name=_('Version'), - blank=False, - default=0, - editable=False) + verbose_name=_("Version"), blank=False, default=0, editable=False + ) - created_at = models.DateTimeField( - _('created at'), - auto_now_add=True) + created_at = models.DateTimeField(_("created at"), auto_now_add=True) def save(self, *args, **kwargs): repository = self.repository_update.repository @@ -1419,48 +1287,45 @@ def save(self, *args, **kwargs): class RepositoryEvaluateResultIntent(models.Model): class Meta: - db_table = 'common_repository_evaluate_result_intent' + db_table = "common_repository_evaluate_result_intent" evaluate_result = models.ForeignKey( - RepositoryEvaluateResult, - models.CASCADE, - related_name='evaluate_result_intent' + RepositoryEvaluateResult, models.CASCADE, related_name="evaluate_result_intent" ) intent = models.CharField( - _('intent'), + _("intent"), max_length=64, - help_text=_('Evaluate intent reference'), - validators=[validate_item_key]) + help_text=_("Evaluate intent reference"), + validators=[validate_item_key], + ) score = models.ForeignKey( RepositoryEvaluateResultScore, models.CASCADE, - related_name='evaluation_intenties_score', - editable=False) + related_name="evaluation_intenties_score", + editable=False, + ) class RepositoryEvaluateResultEntity(models.Model): class Meta: - db_table = 'common_repository_evaluate_result_entity' + db_table = "common_repository_evaluate_result_entity" evaluate_result = models.ForeignKey( - RepositoryEvaluateResult, - models.CASCADE, - related_name='evaluate_result_entity' + RepositoryEvaluateResult, models.CASCADE, related_name="evaluate_result_entity" ) entity = models.ForeignKey( - RepositoryEntity, - models.CASCADE, - related_name='entity', - editable=False) + RepositoryEntity, models.CASCADE, related_name="entity", editable=False + ) score = models.ForeignKey( RepositoryEvaluateResultScore, models.CASCADE, - related_name='evaluation_entities_score', - editable=False) + related_name="evaluation_entities_score", + editable=False, + ) objects = EntityBaseManager() @@ -1476,16 +1341,13 @@ def set_user_role_on_approved(instance, **kwargs): if not current: return False - if current.approved_by is None and \ - current.approved_by is not instance.approved_by: - user_authorization = instance.repository.get_user_authorization( - instance.user) + if current.approved_by is None and current.approved_by is not instance.approved_by: + user_authorization = instance.repository.get_user_authorization(instance.user) user_authorization.role = RepositoryAuthorization.ROLE_USER - user_authorization.save(update_fields=['role']) + user_authorization.save(update_fields=["role"]) instance.send_request_approved_email() else: - raise ValidationError( - _('You can change approved_by just one time.')) + raise ValidationError(_("You can change approved_by just one time.")) @receiver(models.signals.post_save, sender=RequestRepositoryAuthorization) diff --git a/bothub/common/tests.py b/bothub/common/tests.py index aebcb6b6..ada8e3b3 100644 --- a/bothub/common/tests.py +++ b/bothub/common/tests.py @@ -23,209 +23,150 @@ class RepositoryUpdateTestCase(TestCase): def setUp(self): - owner = User.objects.create_user('fake@user.com', 'user', '123456') - self.repository = Repository.objects.create( - owner=owner, - slug='test') - self.repository_update = self.repository.current_update('en') + owner = User.objects.create_user("fake@user.com", "user", "123456") + self.repository = Repository.objects.create(owner=owner, slug="test") + self.repository_update = self.repository.current_update("en") example = RepositoryExample.objects.create( - repository_update=self.repository_update, - text='my name is User') + repository_update=self.repository_update, text="my name is User" + ) self.entity = RepositoryExampleEntity.objects.create( - repository_example=example, - start=11, - end=18, - entity='name') + repository_example=example, start=11, end=18, entity="name" + ) def test_repository_example_entity(self): - self.assertEqual(self.entity.value, 'User') + self.assertEqual(self.entity.value, "User") def test_repository_current_update(self): - update1 = self.repository.current_update('en') - self.assertEqual(update1, self.repository.current_update('en')) + update1 = self.repository.current_update("en") + self.assertEqual(update1, self.repository.current_update("en")) update1.training_started_at = timezone.now() update1.save() - self.assertNotEqual(update1, self.repository.current_update('en')) + self.assertNotEqual(update1, self.repository.current_update("en")) class TranslateTestCase(TestCase): EXPECTED_RASA_NLU_DATA = { - 'text': 'meu nome é User', - 'intent': 'greet', - 'entities': [], + "text": "meu nome é User", + "intent": "greet", + "entities": [], } EXPECTED_RASA_NLU_DATA_WITH_ENTITIES = { - 'text': 'meu nome é User', - 'intent': 'greet', - 'entities': [ - { - 'start': 11, - 'end': 18, - 'value': 'User', - 'entity': 'name', - } - ], + "text": "meu nome é User", + "intent": "greet", + "entities": [{"start": 11, "end": 18, "value": "User", "entity": "name"}], } def setUp(self): - owner = User.objects.create_user('fake@user.com', 'user', '123456') + owner = User.objects.create_user("fake@user.com", "user", "123456") self.repository = Repository.objects.create( - owner=owner, - slug='test', - language=languages.LANGUAGE_EN) - self.repository_update = self.repository.current_update('en') + owner=owner, slug="test", language=languages.LANGUAGE_EN + ) + self.repository_update = self.repository.current_update("en") self.example = RepositoryExample.objects.create( repository_update=self.repository_update, - text='my name is User', - intent='greet') + text="my name is User", + intent="greet", + ) def test_new_translate(self): language = languages.LANGUAGE_PT RepositoryTranslatedExample.objects.create( - original_example=self.example, - language=language, - text='meu nome é User') - self.assertEqual( - len(self.repository.current_update(language).examples), - 1) + original_example=self.example, language=language, text="meu nome é User" + ) + self.assertEqual(len(self.repository.current_update(language).examples), 1) def test_translated_entity(self): RepositoryExampleEntity.objects.create( - repository_example=self.example, - start=11, - end=18, - entity='name') + repository_example=self.example, start=11, end=18, entity="name" + ) language = languages.LANGUAGE_PT translate = RepositoryTranslatedExample.objects.create( - original_example=self.example, - language=language, - text='meu nome é User') + original_example=self.example, language=language, text="meu nome é User" + ) RepositoryTranslatedExampleEntity.objects.create( - repository_translated_example=translate, - start=11, - end=18, - entity='name') + repository_translated_example=translate, start=11, end=18, entity="name" + ) def test_valid_entities(self): RepositoryExampleEntity.objects.create( - repository_example=self.example, - start=12, - end=19, - entity='name') + repository_example=self.example, start=12, end=19, entity="name" + ) language = languages.LANGUAGE_PT translate = RepositoryTranslatedExample.objects.create( - original_example=self.example, - language=language, - text='meu nome é User') + original_example=self.example, language=language, text="meu nome é User" + ) RepositoryTranslatedExampleEntity.objects.create( - repository_translated_example=translate, - start=11, - end=18, - entity='name') + repository_translated_example=translate, start=11, end=18, entity="name" + ) - self.assertEqual( - translate.has_valid_entities, - True) + self.assertEqual(translate.has_valid_entities, True) def test_invalid_count_entities(self): RepositoryExampleEntity.objects.create( - repository_example=self.example, - start=12, - end=19, - entity='name') + repository_example=self.example, start=12, end=19, entity="name" + ) language = languages.LANGUAGE_PT translate = RepositoryTranslatedExample.objects.create( - original_example=self.example, - language=language, - text='meu nome é User') + original_example=self.example, language=language, text="meu nome é User" + ) - self.assertEqual( - translate.has_valid_entities, - False) + self.assertEqual(translate.has_valid_entities, False) RepositoryTranslatedExampleEntity.objects.create( - repository_translated_example=translate, - start=11, - end=18, - entity='name') + repository_translated_example=translate, start=11, end=18, entity="name" + ) RepositoryTranslatedExampleEntity.objects.create( - repository_translated_example=translate, - start=0, - end=3, - entity='my') + repository_translated_example=translate, start=0, end=3, entity="my" + ) - self.assertEqual( - translate.has_valid_entities, - False) + self.assertEqual(translate.has_valid_entities, False) def test_invalid_how_entities(self): RepositoryExampleEntity.objects.create( - repository_example=self.example, - start=12, - end=19, - entity='name') + repository_example=self.example, start=12, end=19, entity="name" + ) language = languages.LANGUAGE_PT translate = RepositoryTranslatedExample.objects.create( - original_example=self.example, - language=language, - text='meu nome é User') + original_example=self.example, language=language, text="meu nome é User" + ) RepositoryTranslatedExampleEntity.objects.create( - repository_translated_example=translate, - start=11, - end=18, - entity='nome') + repository_translated_example=translate, start=11, end=18, entity="nome" + ) - self.assertEqual( - translate.has_valid_entities, - False) + self.assertEqual(translate.has_valid_entities, False) def test_invalid_many_how_entities(self): RepositoryExampleEntity.objects.create( - repository_example=self.example, - start=12, - end=19, - entity='name') + repository_example=self.example, start=12, end=19, entity="name" + ) RepositoryExampleEntity.objects.create( - repository_example=self.example, - start=11, - end=19, - entity='name') + repository_example=self.example, start=11, end=19, entity="name" + ) RepositoryExampleEntity.objects.create( - repository_example=self.example, - start=11, - end=12, - entity='space') + repository_example=self.example, start=11, end=12, entity="space" + ) language = languages.LANGUAGE_PT translate = RepositoryTranslatedExample.objects.create( - original_example=self.example, - language=language, - text='meu nome é User') + original_example=self.example, language=language, text="meu nome é User" + ) RepositoryTranslatedExampleEntity.objects.create( - repository_translated_example=translate, - start=11, - end=18, - entity='name') + repository_translated_example=translate, start=11, end=18, entity="name" + ) RepositoryTranslatedExampleEntity.objects.create( - repository_translated_example=translate, - start=10, - end=11, - entity='space') + repository_translated_example=translate, start=10, end=11, entity="space" + ) RepositoryTranslatedExampleEntity.objects.create( - repository_translated_example=translate, - start=10, - end=11, - entity='space') + repository_translated_example=translate, start=10, end=11, entity="space" + ) - self.assertEqual( - translate.has_valid_entities, - False) + self.assertEqual(translate.has_valid_entities, False) def test_does_not_have_translation(self): with self.assertRaises(DoesNotHaveTranslation): @@ -234,45 +175,39 @@ def test_does_not_have_translation(self): class RepositoryTestCase(TestCase): def setUp(self): - self.owner = User.objects.create_user('owner@user.com', 'owner') - self.user = User.objects.create_user('fake@user.com', 'user') + self.owner = User.objects.create_user("owner@user.com", "owner") + self.user = User.objects.create_user("fake@user.com", "user") self.repository = Repository.objects.create( - owner=self.owner, - name='Test', - slug='test', - language=languages.LANGUAGE_EN) + owner=self.owner, name="Test", slug="test", language=languages.LANGUAGE_EN + ) self.private_repository = Repository.objects.create( - owner=self.owner, - name='Test', - slug='private', - is_private=True) + owner=self.owner, name="Test", slug="private", is_private=True + ) example_1 = RepositoryExample.objects.create( - repository_update=self.repository.current_update( - languages.LANGUAGE_EN), - text='hi', - intent='greet') + repository_update=self.repository.current_update(languages.LANGUAGE_EN), + text="hi", + intent="greet", + ) RepositoryTranslatedExample.objects.create( - original_example=example_1, - language=languages.LANGUAGE_PT, - text='oi') + original_example=example_1, language=languages.LANGUAGE_PT, text="oi" + ) RepositoryTranslatedExample.objects.create( - original_example=example_1, - language=languages.LANGUAGE_ES, - text='hola') + original_example=example_1, language=languages.LANGUAGE_ES, text="hola" + ) RepositoryExample.objects.create( - repository_update=self.repository.current_update( - languages.LANGUAGE_PT), - text='olá', - intent='greet') + repository_update=self.repository.current_update(languages.LANGUAGE_PT), + text="olá", + intent="greet", + ) def test_languages_status(self): languages_status = self.repository.languages_status self.assertListEqual( - list(languages_status.keys()), - list(settings.SUPPORTED_LANGUAGES.keys())) + list(languages_status.keys()), list(settings.SUPPORTED_LANGUAGES.keys()) + ) # TODO: Update test_languages_status test # Create expeted result @@ -282,14 +217,10 @@ def test_last_trained_update(self): update_1.start_training(self.owner) update_2 = self.repository.current_update() update_2.start_training(self.owner) - update_1.save_training(b'bot') - self.assertEqual( - update_1, - self.repository.last_trained_update()) + update_1.save_training(b"bot") + self.assertEqual(update_1, self.repository.last_trained_update()) update_2.train_fail() - self.assertEqual( - update_1, - self.repository.last_trained_update()) + self.assertEqual(update_1, self.repository.last_trained_update()) self.assertEqual(self.repository.total_updates, 1) def test_available_languages(self): @@ -300,239 +231,201 @@ def test_available_languages(self): self.assertEqual(len(available_languages), 3) def test_intents(self): - self.assertIn( - 'greet', - self.repository.intents) + self.assertIn("greet", self.repository.intents) example = RepositoryExample.objects.create( - repository_update=self.repository.current_update( - languages.LANGUAGE_PT), - text='tchau', - intent='bye') - - self.assertIn( - 'greet', - self.repository.intents) - self.assertIn( - 'bye', - self.repository.intents) + repository_update=self.repository.current_update(languages.LANGUAGE_PT), + text="tchau", + intent="bye", + ) + + self.assertIn("greet", self.repository.intents) + self.assertIn("bye", self.repository.intents) example.delete() - self.assertNotIn( - 'bye', - self.repository.intents) + self.assertNotIn("bye", self.repository.intents) def test_entities(self): example = RepositoryExample.objects.create( - repository_update=self.repository.current_update( - languages.LANGUAGE_EN), - text='my name is User') + repository_update=self.repository.current_update(languages.LANGUAGE_EN), + text="my name is User", + ) RepositoryExampleEntity.objects.create( - repository_example=example, - start=11, - end=18, - entity='name') + repository_example=example, start=11, end=18, entity="name" + ) - self.assertIn( - 'name', - self.repository.entities.values_list('value', flat=True)) + self.assertIn("name", self.repository.entities.values_list("value", flat=True)) def test_not_blank_value_in_intents(self): RepositoryExample.objects.create( - repository_update=self.repository.current_update( - languages.LANGUAGE_EN), - text='hi') + repository_update=self.repository.current_update(languages.LANGUAGE_EN), + text="hi", + ) - self.assertNotIn( - '', - self.repository.intents) + self.assertNotIn("", self.repository.intents) class RepositoryExampleTestCase(TestCase): def setUp(self): self.language = languages.LANGUAGE_EN - self.owner = User.objects.create_user('owner@user.com', 'user') + self.owner = User.objects.create_user("owner@user.com", "user") self.repository = Repository.objects.create( - owner=self.owner, - name='Test', - slug='test', - language=self.language) + owner=self.owner, name="Test", slug="test", language=self.language + ) self.example = RepositoryExample.objects.create( repository_update=self.repository.current_update(), - text='hi', - intent='greet') + text="hi", + intent="greet", + ) def test_language(self): - self.assertEqual( - self.example.language, - self.example.repository_update.language) - self.assertEqual( - self.example.language, - self.language) + self.assertEqual(self.example.language, self.example.repository_update.language) + self.assertEqual(self.example.language, self.language) def test_delete(self): self.example.delete() - self.assertEqual( - self.example.deleted_in, - self.repository.current_update()) + self.assertEqual(self.example.deleted_in, self.repository.current_update()) class RepositoryAuthorizationTestCase(TestCase): def setUp(self): - self.owner = User.objects.create_user('owner@user.com', 'owner') - self.user = User.objects.create_user('fake@user.com', 'user') + self.owner = User.objects.create_user("owner@user.com", "owner") + self.user = User.objects.create_user("fake@user.com", "user") self.repository = Repository.objects.create( - owner=self.owner, - name='Test', - slug='test') + owner=self.owner, name="Test", slug="test" + ) self.private_repository = Repository.objects.create( - owner=self.owner, - name='Test', - slug='private', - is_private=True) + owner=self.owner, name="Test", slug="private", is_private=True + ) def test_admin_level(self): authorization = self.repository.get_user_authorization(self.owner) - self.assertEqual( - authorization.level, - RepositoryAuthorization.LEVEL_ADMIN) + self.assertEqual(authorization.level, RepositoryAuthorization.LEVEL_ADMIN) def test_read_level(self): authorization = self.repository.get_user_authorization(self.user) - self.assertEqual( - authorization.level, - RepositoryAuthorization.LEVEL_READER) + self.assertEqual(authorization.level, RepositoryAuthorization.LEVEL_READER) def test_nothing_level(self): - authorization = self.private_repository.get_user_authorization( - self.user) - self.assertEqual( - authorization.level, - RepositoryAuthorization.LEVEL_NOTHING) + authorization = self.private_repository.get_user_authorization(self.user) + self.assertEqual(authorization.level, RepositoryAuthorization.LEVEL_NOTHING) def test_can_read(self): # repository owner - authorization_owner = self.repository.get_user_authorization( - self.owner) + authorization_owner = self.repository.get_user_authorization(self.owner) self.assertTrue(authorization_owner.can_read) # secondary user in public repository - authorization_user = self.repository.get_user_authorization( - self.user) + authorization_user = self.repository.get_user_authorization(self.user) self.assertTrue(authorization_user.can_read) # private repository owner - private_authorization_owner = self.private_repository \ - .get_user_authorization(self.owner) + private_authorization_owner = self.private_repository.get_user_authorization( + self.owner + ) self.assertTrue(private_authorization_owner.can_read) # secondary user in private repository - private_authorization_user = self.private_repository \ - .get_user_authorization(self.user) + private_authorization_user = self.private_repository.get_user_authorization( + self.user + ) self.assertFalse(private_authorization_user.can_read) def test_can_contribute(self): # repository owner - authorization_owner = self.repository.get_user_authorization( - self.owner) + authorization_owner = self.repository.get_user_authorization(self.owner) self.assertTrue(authorization_owner.can_contribute) # secondary user in public repository - authorization_user = self.repository.get_user_authorization( - self.user) + authorization_user = self.repository.get_user_authorization(self.user) self.assertFalse(authorization_user.can_contribute) # private repository owner - private_authorization_owner = self.private_repository \ - .get_user_authorization(self.owner) + private_authorization_owner = self.private_repository.get_user_authorization( + self.owner + ) self.assertTrue(private_authorization_owner.can_contribute) # secondary user in private repository - private_authorization_user = self.private_repository \ - .get_user_authorization(self.user) + private_authorization_user = self.private_repository.get_user_authorization( + self.user + ) self.assertFalse(private_authorization_user.can_contribute) def test_can_write(self): # repository owner - authorization_owner = self.repository.get_user_authorization( - self.owner) + authorization_owner = self.repository.get_user_authorization(self.owner) self.assertTrue(authorization_owner.can_write) # secondary user in public repository - authorization_user = self.repository.get_user_authorization( - self.user) + authorization_user = self.repository.get_user_authorization(self.user) self.assertFalse(authorization_user.can_write) # private repository owner - private_authorization_owner = self.private_repository \ - .get_user_authorization(self.owner) + private_authorization_owner = self.private_repository.get_user_authorization( + self.owner + ) self.assertTrue(private_authorization_owner.can_write) # secondary user in private repository - private_authorization_user = self.private_repository \ - .get_user_authorization(self.user) + private_authorization_user = self.private_repository.get_user_authorization( + self.user + ) self.assertFalse(private_authorization_user.can_write) def test_is_admin(self): # repository owner - authorization_owner = self.repository.get_user_authorization( - self.owner) + authorization_owner = self.repository.get_user_authorization(self.owner) self.assertTrue(authorization_owner.is_admin) # secondary user in public repository - authorization_user = self.repository.get_user_authorization( - self.user) + authorization_user = self.repository.get_user_authorization(self.user) self.assertFalse(authorization_user.is_admin) # private repository owner - private_authorization_owner = self.private_repository \ - .get_user_authorization(self.owner) + private_authorization_owner = self.private_repository.get_user_authorization( + self.owner + ) self.assertTrue(private_authorization_owner.is_admin) # secondary user in private repository - private_authorization_user = self.private_repository \ - .get_user_authorization(self.user) + private_authorization_user = self.private_repository.get_user_authorization( + self.user + ) self.assertFalse(private_authorization_user.is_admin) def test_owner_ever_admin(self): - authorization_owner = self.repository.get_user_authorization( - self.owner) + authorization_owner = self.repository.get_user_authorization(self.owner) self.assertTrue(authorization_owner.is_admin) def test_role_user_can_read(self): # public repository - authorization_user = self.repository.get_user_authorization( - self.user) + authorization_user = self.repository.get_user_authorization(self.user) authorization_user.role = RepositoryAuthorization.ROLE_USER authorization_user.save() self.assertTrue(authorization_user.can_read) # private repository - authorization_user = self.private_repository.get_user_authorization( - self.user) + authorization_user = self.private_repository.get_user_authorization(self.user) authorization_user.role = RepositoryAuthorization.ROLE_USER authorization_user.save() self.assertTrue(authorization_user.can_read) def test_role_user_can_t_contribute(self): # public repository - authorization_user = self.repository.get_user_authorization( - self.user) + authorization_user = self.repository.get_user_authorization(self.user) authorization_user.role = RepositoryAuthorization.ROLE_USER authorization_user.save() self.assertFalse(authorization_user.can_contribute) # private repository - authorization_user = self.private_repository.get_user_authorization( - self.user) + authorization_user = self.private_repository.get_user_authorization(self.user) authorization_user.role = RepositoryAuthorization.ROLE_USER authorization_user.save() self.assertFalse(authorization_user.can_contribute) def test_role_contributor_can_contribute(self): # public repository - authorization_user = self.repository.get_user_authorization( - self.user) + authorization_user = self.repository.get_user_authorization(self.user) authorization_user.role = RepositoryAuthorization.ROLE_CONTRIBUTOR authorization_user.save() self.assertTrue(authorization_user.can_contribute) # private repository - authorization_user = self.private_repository.get_user_authorization( - self.user) + authorization_user = self.private_repository.get_user_authorization(self.user) authorization_user.role = RepositoryAuthorization.ROLE_CONTRIBUTOR authorization_user.save() self.assertTrue(authorization_user.can_contribute) @@ -540,24 +433,20 @@ def test_role_contributor_can_contribute(self): class RepositoryUpdateTrainingTestCase(TestCase): def setUp(self): - self.owner = User.objects.create_user('owner@user.com', 'user') + self.owner = User.objects.create_user("owner@user.com", "user") self.repository = Repository.objects.create( - owner=self.owner, - name='Test', - slug='test', - language=languages.LANGUAGE_EN) + owner=self.owner, name="Test", slug="test", language=languages.LANGUAGE_EN + ) def test_train(self): update = self.repository.current_update() update.start_training(self.owner) - bot_data = 'https://s3.amazonaws.com' + bot_data = "https://s3.amazonaws.com" update.save_training(bot_data) - self.assertEqual( - update.get_bot_data(), - bot_data) + self.assertEqual(update.get_bot_data(), bot_data) def test_already_started_trained(self): update = self.repository.current_update() @@ -568,7 +457,7 @@ def test_already_started_trained(self): def test_already_trained(self): update = self.repository.current_update() update.start_training(self.owner) - update.save_training(b'') + update.save_training(b"") with self.assertRaises(RepositoryUpdateAlreadyTrained): update.start_training(self.owner) @@ -577,7 +466,7 @@ def test_already_trained(self): update.save_training(self.owner) def test_training_not_allowed(self): - user = User.objects.create_user('fake@user.com', 'fake') + user = User.objects.create_user("fake@user.com", "fake") update = self.repository.current_update() with self.assertRaises(TrainingNotAllowed): @@ -586,146 +475,125 @@ def test_training_not_allowed(self): class RepositoryUpdateExamplesTestCase(TestCase): def setUp(self): - self.owner = User.objects.create_user('owner@user.com', 'user') + self.owner = User.objects.create_user("owner@user.com", "user") self.repository = Repository.objects.create( - owner=self.owner, - name='Test', - slug='test', - language=languages.LANGUAGE_EN) + owner=self.owner, name="Test", slug="test", language=languages.LANGUAGE_EN + ) RepositoryExample.objects.create( repository_update=self.repository.current_update(), - text='hi', - intent='greet') + text="hi", + intent="greet", + ) example = RepositoryExample.objects.create( repository_update=self.repository.current_update(), - text='hello1', - intent='greet') + text="hello1", + intent="greet", + ) example.delete() self.update = self.repository.current_update() self.update.start_training(self.owner) - self.update.save_training(b'') + self.update.save_training(b"") def test_okay(self): new_update_1 = self.repository.current_update() RepositoryExample.objects.create( - repository_update=new_update_1, - text='hello', - intent='greet') + repository_update=new_update_1, text="hello", intent="greet" + ) new_update_1.start_training(self.owner) new_update_2 = self.repository.current_update() RepositoryExample.objects.create( - repository_update=new_update_2, - text='good morning', - intent='greet') - - self.assertEqual( - self.update.examples.count(), - 1) - self.assertEqual( - new_update_1.examples.count(), - 2) - self.assertEqual( - new_update_2.examples.count(), - 3) + repository_update=new_update_2, text="good morning", intent="greet" + ) + + self.assertEqual(self.update.examples.count(), 1) + self.assertEqual(new_update_1.examples.count(), 2) + self.assertEqual(new_update_2.examples.count(), 3) def test_examples_deleted_consistency(self): new_update_1 = self.repository.current_update() RepositoryExample.objects.create( - repository_update=new_update_1, - text='hello', - intent='greet') + repository_update=new_update_1, text="hello", intent="greet" + ) RepositoryExample.objects.create( - repository_update=new_update_1, - text='hello d1', - intent='greet').delete() + repository_update=new_update_1, text="hello d1", intent="greet" + ).delete() examples_1_count = new_update_1.examples.count() new_update_1.start_training(self.owner) new_update_2 = self.repository.current_update() RepositoryExample.objects.create( - repository_update=new_update_2, - text='hellow', - intent='greet') + repository_update=new_update_2, text="hellow", intent="greet" + ) examples_2_count = new_update_2.examples.count() new_update_2.start_training(self.owner) new_update_3 = self.repository.current_update() RepositoryExample.objects.create( - repository_update=new_update_3, - text='hellow', - intent='greet') + repository_update=new_update_3, text="hellow", intent="greet" + ) RepositoryExample.objects.create( - repository_update=new_update_3, - text='hello d2', - intent='greet').delete() + repository_update=new_update_3, text="hello d2", intent="greet" + ).delete() RepositoryExample.objects.create( - repository_update=new_update_3, - text='hello d3', - intent='greet').delete() + repository_update=new_update_3, text="hello d3", intent="greet" + ).delete() RepositoryExample.objects.create( - repository_update=new_update_3, - text='hello d4', - intent='greet').delete() + repository_update=new_update_3, text="hello d4", intent="greet" + ).delete() examples_3_count = new_update_3.examples.count() new_update_3.start_training(self.owner) new_update_4 = self.repository.current_update() RepositoryExample.objects.create( - repository_update=new_update_4, - text='hellow', - intent='greet') + repository_update=new_update_4, text="hellow", intent="greet" + ) examples_4_count = new_update_4.examples.count() new_update_4.start_training(self.owner) - self.assertEqual( - examples_1_count, - new_update_1.examples.count()) + self.assertEqual(examples_1_count, new_update_1.examples.count()) - self.assertEqual( - examples_2_count, - new_update_2.examples.count()) + self.assertEqual(examples_2_count, new_update_2.examples.count()) - self.assertEqual( - examples_3_count, - new_update_3.examples.count()) + self.assertEqual(examples_3_count, new_update_3.examples.count()) - self.assertEqual( - examples_4_count, - new_update_4.examples.count()) + self.assertEqual(examples_4_count, new_update_4.examples.count()) class RepositoryReadyForTrain(TestCase): def setUp(self): - self.owner = User.objects.create_user('owner@user.com', 'user') + self.owner = User.objects.create_user("owner@user.com", "user") self.repository = Repository.objects.create( - owner=self.owner, - name='Test', - slug='test', - language=languages.LANGUAGE_EN) + owner=self.owner, name="Test", slug="test", language=languages.LANGUAGE_EN + ) self.example_1 = RepositoryExample.objects.create( repository_update=self.repository.current_update(), - text='hi', - intent='greet') + text="hi", + intent="greet", + ) self.example_2 = RepositoryExample.objects.create( repository_update=self.repository.current_update(), - text='hello', - intent='greet') + text="hello", + intent="greet", + ) self.example_3 = RepositoryExample.objects.create( repository_update=self.repository.current_update(), - text='bye!', - intent='bye') + text="bye!", + intent="bye", + ) self.example_4 = RepositoryExample.objects.create( repository_update=self.repository.current_update(), - text='good bye', - intent='bye') + text="good bye", + intent="bye", + ) self.example_5 = RepositoryExample.objects.create( repository_update=self.repository.current_update(), - text='hellow', - intent='greet') + text="hellow", + intent="greet", + ) def test_be_true(self): self.assertTrue(self.repository.ready_for_train) @@ -737,13 +605,11 @@ def test_be_false(self): def test_be_true_when_new_translate(self): self.repository.current_update().start_training(self.owner) RepositoryTranslatedExample.objects.create( - original_example=self.example_1, - language=languages.LANGUAGE_PT, - text='oi') + original_example=self.example_1, language=languages.LANGUAGE_PT, text="oi" + ) RepositoryTranslatedExample.objects.create( - original_example=self.example_2, - language=languages.LANGUAGE_PT, - text='olá') + original_example=self.example_2, language=languages.LANGUAGE_PT, text="olá" + ) self.repository.current_update() self.assertTrue(self.repository.ready_for_train) @@ -769,7 +635,7 @@ def test_change_algorithm(self): self.repository.save() current_update = self.repository.current_update() current_update.start_training(self.owner) - current_update.save_training(b'') + current_update.save_training(b"") self.assertFalse(self.repository.ready_for_train) self.repository.algorithm = val_next self.repository.save() @@ -778,24 +644,27 @@ def test_change_algorithm(self): class RepositoryUpdateReadyForTrain(TestCase): def setUp(self): - self.owner = User.objects.create_user('owner@user.com', 'user') + self.owner = User.objects.create_user("owner@user.com", "user") self.repository = Repository.objects.create( owner=self.owner, - name='Test', - slug='test', + name="Test", + slug="test", language=languages.LANGUAGE_EN, - algorithm=Repository.ALGORITHM_NEURAL_NETWORK_INTERNAL) + algorithm=Repository.ALGORITHM_NEURAL_NETWORK_INTERNAL, + ) def test_be_true(self): RepositoryExample.objects.create( repository_update=self.repository.current_update(), - text='hi', - intent='greet') + text="hi", + intent="greet", + ) RepositoryExample.objects.create( repository_update=self.repository.current_update(), - text='hi', - intent='greet') + text="hi", + intent="greet", + ) self.assertTrue(self.repository.current_update().ready_for_train) def test_be_false(self): @@ -804,110 +673,106 @@ def test_be_false(self): def test_new_translate(self): example_1 = RepositoryExample.objects.create( repository_update=self.repository.current_update(), - text='hi', - intent='greet') + text="hi", + intent="greet", + ) example_2 = RepositoryExample.objects.create( repository_update=self.repository.current_update(), - text='hello', - intent='greet') + text="hello", + intent="greet", + ) self.repository.current_update().start_training(self.owner) RepositoryTranslatedExample.objects.create( - original_example=example_1, - language=languages.LANGUAGE_PT, - text='oi') + original_example=example_1, language=languages.LANGUAGE_PT, text="oi" + ) RepositoryTranslatedExample.objects.create( - original_example=example_2, - language=languages.LANGUAGE_PT, - text='olá') - self.assertTrue(self.repository.current_update( - languages.LANGUAGE_PT).ready_for_train) + original_example=example_2, language=languages.LANGUAGE_PT, text="olá" + ) + self.assertTrue( + self.repository.current_update(languages.LANGUAGE_PT).ready_for_train + ) def test_when_deleted(self): example = RepositoryExample.objects.create( repository_update=self.repository.current_update(), - text='hi', - intent='greet') + text="hi", + intent="greet", + ) RepositoryExample.objects.create( repository_update=self.repository.current_update(), - text='hello', - intent='greet') + text="hello", + intent="greet", + ) RepositoryExample.objects.create( repository_update=self.repository.current_update(), - text='hellow', - intent='greet') + text="hellow", + intent="greet", + ) self.repository.current_update().start_training(self.owner) example.delete() self.assertTrue(self.repository.current_update().ready_for_train) def test_empty_intent(self): example = RepositoryExample.objects.create( - repository_update=self.repository.current_update(), - text='user', - intent='') + repository_update=self.repository.current_update(), text="user", intent="" + ) RepositoryExample.objects.create( - repository_update=self.repository.current_update(), - text='user', - intent='') + repository_update=self.repository.current_update(), text="user", intent="" + ) RepositoryExampleEntity.objects.create( - repository_example=example, - start=0, - end=7, - entity='name') + repository_example=example, start=0, end=7, entity="name" + ) RepositoryExampleEntity.objects.create( - repository_example=example, - start=0, - end=7, - entity='name') + repository_example=example, start=0, end=7, entity="name" + ) self.assertFalse(self.repository.current_update().ready_for_train) def test_intent_dont_have_min_examples(self): RepositoryExample.objects.create( repository_update=self.repository.current_update(), - text='hi', - intent='greet') + text="hi", + intent="greet", + ) self.assertFalse(self.repository.current_update().ready_for_train) def test_entity_dont_have_min_examples(self): example = RepositoryExample.objects.create( repository_update=self.repository.current_update(), - text='hi', - intent='greet') + text="hi", + intent="greet", + ) RepositoryExample.objects.create( repository_update=self.repository.current_update(), - text='hello', - intent='greet') + text="hello", + intent="greet", + ) RepositoryExampleEntity.objects.create( - repository_example=example, - start=0, - end=2, - entity='hi') + repository_example=example, start=0, end=2, entity="hi" + ) self.assertFalse(self.repository.current_update().ready_for_train) RepositoryExampleEntity.objects.create( - repository_example=example, - start=1, - end=2, - entity='hi') + repository_example=example, start=1, end=2, entity="hi" + ) self.assertTrue(self.repository.current_update().ready_for_train) def test_settings_change_exists_requirements(self): self.repository.current_update().start_training(self.owner) - self.repository.algorithm = Repository \ - .ALGORITHM_NEURAL_NETWORK_EXTERNAL + self.repository.algorithm = Repository.ALGORITHM_NEURAL_NETWORK_EXTERNAL self.repository.save() RepositoryExample.objects.create( repository_update=self.repository.current_update(), - text='hello', - intent='greet') - self.assertEqual( - len(self.repository.current_update().requirements_to_train), - 1) + text="hello", + intent="greet", + ) + self.assertEqual(len(self.repository.current_update().requirements_to_train), 1) self.assertFalse(self.repository.current_update().ready_for_train) def test_no_examples(self): example = RepositoryExample.objects.create( repository_update=self.repository.current_update(), - text='hi', - intent='greet') + text="hi", + intent="greet", + ) self.repository.current_update().start_training(self.owner) example.delete() self.assertFalse(self.repository.current_update().ready_for_train) @@ -915,18 +780,15 @@ def test_no_examples(self): class RequestRepositoryAuthorizationTestCase(TestCase): def setUp(self): - self.owner = User.objects.create_user('owner@user.com', 'owner') + self.owner = User.objects.create_user("owner@user.com", "owner") repository = Repository.objects.create( - owner=self.owner, - name='Test', - slug='test', - language=languages.LANGUAGE_EN) - self.user = User.objects.create_user('user@user.com', 'user') + owner=self.owner, name="Test", slug="test", language=languages.LANGUAGE_EN + ) + self.user = User.objects.create_user("user@user.com", "user") self.ra = RequestRepositoryAuthorization.objects.create( - user=self.user, - repository=repository, - text='I can contribute') - self.admin = User.objects.create_user('admin@user.com', 'admin') + user=self.user, repository=repository, text="I can contribute" + ) + self.admin = User.objects.create_user("admin@user.com", "admin") admin_authorization = repository.get_user_authorization(self.admin) admin_authorization.role = RepositoryAuthorization.ROLE_ADMIN admin_authorization.save() @@ -934,11 +796,8 @@ def setUp(self): def test_approve(self): self.ra.approved_by = self.owner self.ra.save() - user_authorization = self.ra.repository.get_user_authorization( - self.ra.user) - self.assertEqual( - user_authorization.role, - RepositoryAuthorization.ROLE_USER) + user_authorization = self.ra.repository.get_user_authorization(self.ra.user) + self.assertEqual(user_authorization.role, RepositoryAuthorization.ROLE_USER) def test_approve_twice(self): self.ra.approved_by = self.owner @@ -959,135 +818,109 @@ class RepositoryEntityTestCase(TestCase): def setUp(self): self.language = languages.LANGUAGE_EN - self.owner = User.objects.create_user('owner@user.com', 'user') + self.owner = User.objects.create_user("owner@user.com", "user") self.repository = Repository.objects.create( - owner=self.owner, - name='Test', - slug='test', - language=self.language) + owner=self.owner, name="Test", slug="test", language=self.language + ) self.example = RepositoryExample.objects.create( - repository_update=self.repository.current_update(), - text='my name is User') + repository_update=self.repository.current_update(), text="my name is User" + ) self.example_entity_1 = RepositoryExampleEntity.objects.create( - repository_example=self.example, - start=11, - end=18, - entity='name') + repository_example=self.example, start=11, end=18, entity="name" + ) self.example_entity_2 = RepositoryExampleEntity.objects.create( - repository_example=self.example, - start=0, - end=2, - entity='object') + repository_example=self.example, start=0, end=2, entity="object" + ) def test_example_entity_create_entity(self): name_entity = RepositoryEntity.objects.get( - repository=self.repository, - value='name') - self.assertEqual( - name_entity.pk, - self.example_entity_1.entity.pk) + repository=self.repository, value="name" + ) + self.assertEqual(name_entity.pk, self.example_entity_1.entity.pk) def test_dont_duplicate_entity(self): name_entity = RepositoryEntity.objects.get( - repository=self.repository, - value='name') + repository=self.repository, value="name" + ) new_example_entity = RepositoryExampleEntity.objects.create( - repository_example=self.example, - start=11, - end=18, - entity='name') + repository_example=self.example, start=11, end=18, entity="name" + ) - self.assertEqual( - name_entity.pk, - self.example_entity_1.entity.pk) - self.assertEqual( - name_entity.pk, - new_example_entity.entity.pk) + self.assertEqual(name_entity.pk, self.example_entity_1.entity.pk) + self.assertEqual(name_entity.pk, new_example_entity.entity.pk) class RepositoryEntityLabelTestCase(TestCase): def setUp(self): self.language = languages.LANGUAGE_EN - self.owner = User.objects.create_user('owner@user.com', 'user') + self.owner = User.objects.create_user("owner@user.com", "user") self.repository = Repository.objects.create( - owner=self.owner, - name='Test', - slug='test', - language=self.language) + owner=self.owner, name="Test", slug="test", language=self.language + ) self.example = RepositoryExample.objects.create( - repository_update=self.repository.current_update(), - text='my name is User') + repository_update=self.repository.current_update(), text="my name is User" + ) self.example_entity_1 = RepositoryExampleEntity.objects.create( - repository_example=self.example, - start=11, - end=18, - entity='name') + repository_example=self.example, start=11, end=18, entity="name" + ) self.example_entity_2 = RepositoryExampleEntity.objects.create( - repository_example=self.example, - start=0, - end=2, - entity='object') + repository_example=self.example, start=0, end=2, entity="object" + ) def test_set_label(self): name_entity = RepositoryEntity.objects.get( - repository=self.repository, - value='name') + repository=self.repository, value="name" + ) - name_entity.set_label('subject') + name_entity.set_label("subject") self.assertIsNotNone(name_entity.label) def test_entity_label_created(self): name_entity = RepositoryEntity.objects.get( - repository=self.repository, - value='name') + repository=self.repository, value="name" + ) - name_entity.set_label('subject') + name_entity.set_label("subject") subject_label = RepositoryEntityLabel.objects.get( - repository=self.repository, - value='subject') + repository=self.repository, value="subject" + ) - self.assertEqual( - name_entity.label.pk, - subject_label.pk) + self.assertEqual(name_entity.label.pk, subject_label.pk) def test_dont_duplicate_label(self): name_entity = RepositoryEntity.objects.get( - repository=self.repository, - value='name') - name_entity.set_label('subject') + repository=self.repository, value="name" + ) + name_entity.set_label("subject") object_entity = RepositoryEntity.objects.get( - repository=self.repository, - value='object') - object_entity.set_label('subject') + repository=self.repository, value="object" + ) + object_entity.set_label("subject") subject_label = RepositoryEntityLabel.objects.get( - repository=self.repository, - value='subject') + repository=self.repository, value="subject" + ) - self.assertEqual( - name_entity.label.pk, - subject_label.pk) - self.assertEqual( - object_entity.label.pk, - subject_label.pk) + self.assertEqual(name_entity.label.pk, subject_label.pk) + self.assertEqual(object_entity.label.pk, subject_label.pk) def test_set_label_to_none(self): name_entity = RepositoryEntity.objects.get( - repository=self.repository, - value='name') + repository=self.repository, value="name" + ) name_entity.set_label(None) @@ -1096,38 +929,30 @@ def test_set_label_to_none(self): class RepositoryOtherEntitiesTest(TestCase): def setUp(self): - self.owner = User.objects.create_user('owner@user.com', 'user') + self.owner = User.objects.create_user("owner@user.com", "user") self.repository = Repository.objects.create( - owner=self.owner, - name='Test', - slug='test', - language=languages.LANGUAGE_EN) + owner=self.owner, name="Test", slug="test", language=languages.LANGUAGE_EN + ) self.example = RepositoryExample.objects.create( - repository_update=self.repository.current_update(), - text='my name is User') + repository_update=self.repository.current_update(), text="my name is User" + ) self.example_entity_1 = RepositoryExampleEntity.objects.create( - repository_example=self.example, - start=11, - end=18, - entity='user') + repository_example=self.example, start=11, end=18, entity="user" + ) entity = self.example_entity_1.entity - entity.set_label('name') + entity.set_label("name") entity.save() self.example_entity_2 = RepositoryExampleEntity.objects.create( - repository_example=self.example, - start=0, - end=2, - entity='object') + repository_example=self.example, start=0, end=2, entity="object" + ) def test_ok(self): other_entities = self.repository.other_entities - self.assertEqual( - other_entities.count(), - 1) + self.assertEqual(other_entities.count(), 1) self.assertIn(self.example_entity_2.entity, other_entities) @@ -1135,31 +960,33 @@ class UseLanguageModelFeaturizerTestCase(TestCase): def setUp(self): self.language = languages.LANGUAGE_EN - self.owner = User.objects.create_user('owner@user.com', 'user') + self.owner = User.objects.create_user("owner@user.com", "user") self.repository = Repository.objects.create( owner=self.owner, - name='Test', - slug='test', + name="Test", + slug="test", language=self.language, - algorithm=Repository.ALGORITHM_NEURAL_NETWORK_EXTERNAL) + algorithm=Repository.ALGORITHM_NEURAL_NETWORK_EXTERNAL, + ) RepositoryExample.objects.create( repository_update=self.repository.current_update(), - text='my name is user', - intent='greet') + text="my name is user", + intent="greet", + ) RepositoryExample.objects.create( repository_update=self.repository.current_update(), - text='my name is John', - intent='greet') + text="my name is John", + intent="greet", + ) def test_equal_repository_value_after_train(self): current_update = self.repository.current_update() - self.repository.algorithm = Repository \ - .ALGORITHM_NEURAL_NETWORK_INTERNAL + self.repository.algorithm = Repository.ALGORITHM_NEURAL_NETWORK_INTERNAL self.repository.save() current_update.start_training(self.owner) - current_update.save_training(b'') + current_update.save_training(b"") self.assertFalse(current_update.use_language_model_featurizer) @@ -1167,29 +994,32 @@ class UseCompetingIntentsTestCase(TestCase): def setUp(self): self.language = languages.LANGUAGE_EN - self.owner = User.objects.create_user('owner@user.com', 'user') + self.owner = User.objects.create_user("owner@user.com", "user") self.repository = Repository.objects.create( owner=self.owner, - name='Test', - slug='test', + name="Test", + slug="test", language=self.language, - use_competing_intents=True) + use_competing_intents=True, + ) RepositoryExample.objects.create( repository_update=self.repository.current_update(), - text='my name is user', - intent='greet') + text="my name is user", + intent="greet", + ) RepositoryExample.objects.create( repository_update=self.repository.current_update(), - text='my name is John', - intent='greet') + text="my name is John", + intent="greet", + ) def test_change_ready_for_train(self): self.assertTrue(self.repository.ready_for_train) current_update = self.repository.current_update() current_update.start_training(self.owner) - current_update.save_training(b'') + current_update.save_training(b"") self.assertFalse(self.repository.ready_for_train) self.repository.use_competing_intents = False self.repository.save() @@ -1203,7 +1033,7 @@ def test_equal_repository_value_after_train(self): self.repository.use_competing_intents = False self.repository.save() current_update.start_training(self.owner) - current_update.save_training(b'') + current_update.save_training(b"") self.assertFalse(current_update.use_competing_intents) @@ -1211,29 +1041,32 @@ class UseNameEntitiesTestCase(TestCase): def setUp(self): self.language = languages.LANGUAGE_EN - self.owner = User.objects.create_user('owner@user.com', 'user') + self.owner = User.objects.create_user("owner@user.com", "user") self.repository = Repository.objects.create( owner=self.owner, - name='Test', - slug='test', + name="Test", + slug="test", language=self.language, - use_name_entities=True) + use_name_entities=True, + ) RepositoryExample.objects.create( repository_update=self.repository.current_update(), - text='my name is user', - intent='greet') + text="my name is user", + intent="greet", + ) RepositoryExample.objects.create( repository_update=self.repository.current_update(), - text='my name is John', - intent='greet') + text="my name is John", + intent="greet", + ) def test_change_ready_for_train(self): self.assertTrue(self.repository.ready_for_train) current_update = self.repository.current_update() current_update.start_training(self.owner) - current_update.save_training(b'') + current_update.save_training(b"") self.assertFalse(self.repository.ready_for_train) self.repository.use_name_entities = False self.repository.save() @@ -1247,7 +1080,7 @@ def test_equal_repository_value_after_train(self): self.repository.use_name_entities = False self.repository.save() current_update.start_training(self.owner) - current_update.save_training(b'') + current_update.save_training(b"") self.assertFalse(current_update.use_name_entities) @@ -1255,61 +1088,53 @@ class RepositoryUpdateWarnings(TestCase): def setUp(self): self.language = languages.LANGUAGE_EN - self.owner = User.objects.create_user('owner@user.com', 'user') + self.owner = User.objects.create_user("owner@user.com", "user") self.repository = Repository.objects.create( owner=self.owner, - name='Test', - slug='test', + name="Test", + slug="test", language=self.language, - use_competing_intents=True) + use_competing_intents=True, + ) RepositoryExample.objects.create( repository_update=self.repository.current_update(), - text='my name is user', - intent='greet') + text="my name is user", + intent="greet", + ) def test_min_intents(self): - self.assertEqual( - len(self.repository.current_update().warnings), - 1) + self.assertEqual(len(self.repository.current_update().warnings), 1) RepositoryExample.objects.create( - repository_update=self.repository.current_update(), - text='bye', - intent='bye') - self.assertEqual( - len(self.repository.current_update().warnings), - 0) + repository_update=self.repository.current_update(), text="bye", intent="bye" + ) + self.assertEqual(len(self.repository.current_update().warnings), 0) class RepositorySupportedLanguageQueryTestCase(TestCase): def setUp(self): - self.owner = User.objects.create_user('owner@user.com', 'user') + self.owner = User.objects.create_user("owner@user.com", "user") self.uid = 0 def _create_repository(self, language): self.uid += 1 return Repository.objects.create( owner=self.owner, - name='Test {}'.format(language), - slug='test-{}-{}'.format(self.uid, language), - language=language) + name="Test {}".format(language), + slug="test-{}-{}".format(self.uid, language), + language=language, + ) def test_main_language(self): language = languages.LANGUAGE_EN repository_en = self._create_repository(language) q = Repository.objects.all().supported_language(language) - self.assertEqual( - q.count(), - 1, - ) + self.assertEqual(q.count(), 1) self.assertIn(repository_en, q) q = Repository.objects.all().supported_language(language) repository_pt = self._create_repository(languages.LANGUAGE_PT) - self.assertEqual( - q.count(), - 1, - ) + self.assertEqual(q.count(), 1) self.assertNotIn(repository_pt, q) def test_has_translation(self): @@ -1317,18 +1142,13 @@ def test_has_translation(self): t_language = languages.LANGUAGE_PT repository_en = self._create_repository(language) example = RepositoryExample.objects.create( - repository_update=repository_en.current_update(), - text='bye', - intent='bye') + repository_update=repository_en.current_update(), text="bye", intent="bye" + ) RepositoryTranslatedExample.objects.create( - original_example=example, - language=t_language, - text='tchau') - q = Repository.objects.all().supported_language(t_language) - self.assertEqual( - q.count(), - 1, + original_example=example, language=t_language, text="tchau" ) + q = Repository.objects.all().supported_language(t_language) + self.assertEqual(q.count(), 1) self.assertIn(repository_en, q) def test_has_example(self): @@ -1337,17 +1157,12 @@ def test_has_example(self): repository_en = self._create_repository(language) example = RepositoryExample.objects.create( repository_update=repository_en.current_update(e_language), - text='bye', - intent='bye') - q = Repository.objects.all().supported_language(e_language) - self.assertEqual( - q.count(), - 1, + text="bye", + intent="bye", ) + q = Repository.objects.all().supported_language(e_language) + self.assertEqual(q.count(), 1) self.assertIn(repository_en, q) example.delete() q = Repository.objects.all().supported_language(e_language) - self.assertEqual( - q.count(), - 0, - ) + self.assertEqual(q.count(), 0) diff --git a/bothub/common/views.py b/bothub/common/views.py index 53f77ff2..3015bab7 100644 --- a/bothub/common/views.py +++ b/bothub/common/views.py @@ -9,6 +9,6 @@ def download_bot_data(self, update_id): # pragma: no cover update = get_object_or_404(RepositoryUpdate, pk=update_id) if not update.trained_at: - raise ValidationError(f'Update #{update.pk} not trained at.') + raise ValidationError(f"Update #{update.pk} not trained at.") response = HttpResponseRedirect(update.get_bot_data()) return response diff --git a/bothub/health/apps.py b/bothub/health/apps.py index ea5593f6..e860540e 100644 --- a/bothub/health/apps.py +++ b/bothub/health/apps.py @@ -2,4 +2,4 @@ class HealthConfig(AppConfig): - name = 'health' + name = "health" diff --git a/bothub/health/checks.py b/bothub/health/checks.py index 5eb753cd..ab4baac2 100644 --- a/bothub/health/checks.py +++ b/bothub/health/checks.py @@ -4,40 +4,43 @@ from rest_framework import status -logger = logging.getLogger('bothub.health.checks') +logger = logging.getLogger("bothub.health.checks") -CHECK_ACCESSIBLE_API_URL = env.str('CHECK_ACCESSIBLE_API_URL') +CHECK_ACCESSIBLE_API_URL = env.str("CHECK_ACCESSIBLE_API_URL") def check_database_connection(**kwargs): from django.db import connections from django.db.utils import OperationalError + if len(connections.all()) == 0: return False - logger.info('found {} database connection'.format(len(connections.all()))) + logger.info("found {} database connection".format(len(connections.all()))) for i, conn in enumerate(connections.all(), 1): try: conn.cursor() - logger.info('#{} db connection OKAY'.format(i)) + logger.info("#{} db connection OKAY".format(i)) except OperationalError: - logger.warning('#{} db connection ERROR'.format(i)) + logger.warning("#{} db connection ERROR".format(i)) return False return True def check_accessible_api(request, **kwargs): import requests + if CHECK_ACCESSIBLE_API_URL: - logger.info('requesting {}'.format(CHECK_ACCESSIBLE_API_URL)) + logger.info("requesting {}".format(CHECK_ACCESSIBLE_API_URL)) response = requests.get(CHECK_ACCESSIBLE_API_URL) else: - url = 'http://{}/200/'.format( - request.META.get('HTTP_HOST')) - logger.info('requesting to {}'.format(url)) + url = "http://{}/200/".format(request.META.get("HTTP_HOST")) + logger.info("requesting to {}".format(url)) response = requests.get(url) - logger.info('{} response status code {}'.format( - CHECK_ACCESSIBLE_API_URL, - response.status_code)) + logger.info( + "{} response status code {}".format( + CHECK_ACCESSIBLE_API_URL, response.status_code + ) + ) if response.status_code is status.HTTP_200_OK: return True return False diff --git a/bothub/health/views.py b/bothub/health/views.py index 3b77dbf4..976ea3ce 100644 --- a/bothub/health/views.py +++ b/bothub/health/views.py @@ -7,31 +7,22 @@ from .checks import check_database_connection from .checks import check_accessible_api -CHECKS = [ - check_database_connection, - check_accessible_api, -] +CHECKS = [check_database_connection, check_accessible_api] def ping(request): - checks_status = OrderedDict(map( - lambda check: (check.__name__, check(request=request)), - CHECKS)) + checks_status = OrderedDict( + map(lambda check: (check.__name__, check(request=request)), CHECKS) + ) healthy = reduce( - lambda current, status: current and status, - checks_status.values(), - True) - content = '{}\n{}'.format( - 'OK' if healthy else 'something wrong happened', - '\n'.join(map( - lambda x: '{}: {}'.format(*x), - checks_status.items()))) - status_code = status.HTTP_200_OK \ - if healthy else status.HTTP_503_SERVICE_UNAVAILABLE - return HttpResponse( - content=content, - content_type='text/plain', - status=status_code) + lambda current, status: current and status, checks_status.values(), True + ) + content = "{}\n{}".format( + "OK" if healthy else "something wrong happened", + "\n".join(map(lambda x: "{}: {}".format(*x), checks_status.items())), + ) + status_code = status.HTTP_200_OK if healthy else status.HTTP_503_SERVICE_UNAVAILABLE + return HttpResponse(content=content, content_type="text/plain", status=status_code) def r200(request): diff --git a/bothub/settings.py b/bothub/settings.py index 0f908f4b..dc2d90d2 100644 --- a/bothub/settings.py +++ b/bothub/settings.py @@ -8,39 +8,42 @@ from .utils import cast_empty_str_to_none -environ.Env.read_env(env_file=(environ.Path(__file__) - 2)('.env')) +environ.Env.read_env(env_file=(environ.Path(__file__) - 2)(".env")) env = environ.Env( # set casting, default value DEBUG=(bool, False), - ALLOWED_HOSTS=(lambda v: [s.strip() for s in v.split(',')], '*'), - LANGUAGE_CODE=(str, 'en-us'), - TIME_ZONE=(str, 'UTC'), - STATIC_URL=(str, '/static/'), + ALLOWED_HOSTS=(lambda v: [s.strip() for s in v.split(",")], "*"), + LANGUAGE_CODE=(str, "en-us"), + TIME_ZONE=(str, "UTC"), + STATIC_URL=(str, "/static/"), EMAIL_HOST=(cast_empty_str_to_none, None), - ADMINS=(lambda v: [ - ( - s.strip().split('|')[0], - s.strip().split('|')[1], - ) for s in v.split(',')] if v else [], []), - DEFAULT_FROM_EMAIL=(str, 'webmaster@localhost'), - SERVER_EMAIL=(str, 'root@localhost'), + ADMINS=( + lambda v: [ + (s.strip().split("|")[0], s.strip().split("|")[1]) for s in v.split(",") + ] + if v + else [], + [], + ), + DEFAULT_FROM_EMAIL=(str, "webmaster@localhost"), + SERVER_EMAIL=(str, "root@localhost"), EMAIL_PORT=(int, 25), - EMAIL_HOST_USER=(str, ''), - EMAIL_HOST_PASSWORD=(str, ''), + EMAIL_HOST_USER=(str, ""), + EMAIL_HOST_PASSWORD=(str, ""), EMAIL_USE_SSL=(bool, False), EMAIL_USE_TLS=(bool, False), SEND_EMAILS=(bool, True), - BOTHUB_WEBAPP_BASE_URL=(str, 'http://localhost:8080/'), - BOTHUB_NLP_BASE_URL=(str, 'http://localhost:2657/'), + BOTHUB_WEBAPP_BASE_URL=(str, "http://localhost:8080/"), + BOTHUB_NLP_BASE_URL=(str, "http://localhost:2657/"), CSRF_COOKIE_DOMAIN=(cast_empty_str_to_none, None), CSRF_COOKIE_SECURE=(bool, False), - SUPPORTED_LANGUAGES=(cast_supported_languages, 'en|pt'), + SUPPORTED_LANGUAGES=(cast_supported_languages, "en|pt"), CHECK_ACCESSIBLE_API_URL=(str, None), - BOTHUB_ENGINE_AWS_ACCESS_KEY_ID=(str, ''), - BOTHUB_ENGINE_AWS_SECRET_ACCESS_KEY=(str, ''), - BOTHUB_ENGINE_AWS_S3_BUCKET_NAME=(str, ''), - BOTHUB_ENGINE_AWS_REGION_NAME=(str, 'us-east-1') + BOTHUB_ENGINE_AWS_ACCESS_KEY_ID=(str, ""), + BOTHUB_ENGINE_AWS_SECRET_ACCESS_KEY=(str, ""), + BOTHUB_ENGINE_AWS_S3_BUCKET_NAME=(str, ""), + BOTHUB_ENGINE_AWS_REGION_NAME=(str, "us-east-1"), ) # Build paths inside the project like this: os.path.join(BASE_DIR, ...) @@ -48,106 +51,95 @@ # SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = env.str('SECRET_KEY') +SECRET_KEY = env.str("SECRET_KEY") # SECURITY WARNING: don't run with debug turned on in production! -DEBUG = env.bool('DEBUG') +DEBUG = env.bool("DEBUG") -ALLOWED_HOSTS = env.list('ALLOWED_HOSTS') +ALLOWED_HOSTS = env.list("ALLOWED_HOSTS") # Application definition INSTALLED_APPS = [ - 'django.contrib.admin', - 'django.contrib.auth', - 'django.contrib.contenttypes', - 'django.contrib.sessions', - 'django.contrib.messages', - 'django.contrib.staticfiles', - 'rest_framework', - 'rest_framework.authtoken', - 'drf_yasg', - 'django_filters', - 'corsheaders', - 'bothub.authentication', - 'bothub.common', - 'bothub.api', + "django.contrib.admin", + "django.contrib.auth", + "django.contrib.contenttypes", + "django.contrib.sessions", + "django.contrib.messages", + "django.contrib.staticfiles", + "rest_framework", + "rest_framework.authtoken", + "drf_yasg", + "django_filters", + "corsheaders", + "bothub.authentication", + "bothub.common", + "bothub.api", ] MIDDLEWARE = [ - 'django.middleware.security.SecurityMiddleware', - 'whitenoise.middleware.WhiteNoiseMiddleware', - 'django.contrib.sessions.middleware.SessionMiddleware', - 'corsheaders.middleware.CorsMiddleware', - 'django.middleware.common.CommonMiddleware', - 'django.middleware.csrf.CsrfViewMiddleware', - 'django.contrib.auth.middleware.AuthenticationMiddleware', - 'django.contrib.messages.middleware.MessageMiddleware', - 'django.middleware.clickjacking.XFrameOptionsMiddleware', + "django.middleware.security.SecurityMiddleware", + "whitenoise.middleware.WhiteNoiseMiddleware", + "django.contrib.sessions.middleware.SessionMiddleware", + "corsheaders.middleware.CorsMiddleware", + "django.middleware.common.CommonMiddleware", + "django.middleware.csrf.CsrfViewMiddleware", + "django.contrib.auth.middleware.AuthenticationMiddleware", + "django.contrib.messages.middleware.MessageMiddleware", + "django.middleware.clickjacking.XFrameOptionsMiddleware", ] -ROOT_URLCONF = 'bothub.urls' +ROOT_URLCONF = "bothub.urls" TEMPLATES = [ { - 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': [], - 'APP_DIRS': True, - 'OPTIONS': { - 'context_processors': [ - 'django.template.context_processors.debug', - 'django.template.context_processors.request', - 'django.contrib.auth.context_processors.auth', - 'django.contrib.messages.context_processors.messages', - ], + "BACKEND": "django.template.backends.django.DjangoTemplates", + "DIRS": [], + "APP_DIRS": True, + "OPTIONS": { + "context_processors": [ + "django.template.context_processors.debug", + "django.template.context_processors.request", + "django.contrib.auth.context_processors.auth", + "django.contrib.messages.context_processors.messages", + ] }, - }, + } ] -WSGI_APPLICATION = 'bothub.wsgi.application' +WSGI_APPLICATION = "bothub.wsgi.application" # Database -DATABASES = { - 'default': env.db(var='DEFAULT_DATABASE', default='sqlite:///db.sqlite3') -} +DATABASES = {"default": env.db(var="DEFAULT_DATABASE", default="sqlite:///db.sqlite3")} # Auth -AUTH_USER_MODEL = 'authentication.User' +AUTH_USER_MODEL = "authentication.User" # Password validation AUTH_PASSWORD_VALIDATORS = [ { - 'NAME': 'django.contrib.auth.password_validation.' + - 'UserAttributeSimilarityValidator', - }, - { - 'NAME': 'django.contrib.auth.password_validation.' + - 'MinimumLengthValidator', - }, - { - 'NAME': 'django.contrib.auth.password_validation.' + - 'CommonPasswordValidator', - }, - { - 'NAME': 'django.contrib.auth.password_validation.' + - 'NumericPasswordValidator', + "NAME": "django.contrib.auth.password_validation." + + "UserAttributeSimilarityValidator" }, + {"NAME": "django.contrib.auth.password_validation." + "MinimumLengthValidator"}, + {"NAME": "django.contrib.auth.password_validation." + "CommonPasswordValidator"}, + {"NAME": "django.contrib.auth.password_validation." + "NumericPasswordValidator"}, ] # Internationalization -LANGUAGE_CODE = env.str('LANGUAGE_CODE') +LANGUAGE_CODE = env.str("LANGUAGE_CODE") -TIME_ZONE = env.str('TIME_ZONE') +TIME_ZONE = env.str("TIME_ZONE") USE_I18N = True @@ -158,26 +150,23 @@ # Static files (CSS, JavaScript, Images) -STATIC_URL = env.str('STATIC_URL') +STATIC_URL = env.str("STATIC_URL") -STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles') +STATIC_ROOT = os.path.join(BASE_DIR, "staticfiles") -STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage' +STATICFILES_STORAGE = "whitenoise.storage.CompressedManifestStaticFilesStorage" # rest framework REST_FRAMEWORK = { - 'DEFAULT_AUTHENTICATION_CLASSES': [ - 'rest_framework.authentication.TokenAuthentication', - ], - 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.' + - 'LimitOffsetPagination', - 'PAGE_SIZE': 20, - 'DEFAULT_FILTER_BACKENDS': [ - 'django_filters.rest_framework.DjangoFilterBackend', + "DEFAULT_AUTHENTICATION_CLASSES": [ + "rest_framework.authentication.TokenAuthentication" ], - 'DEFAULT_METADATA_CLASS': 'bothub.api.v1.metadata.Metadata', + "DEFAULT_PAGINATION_CLASS": "rest_framework.pagination." + "LimitOffsetPagination", + "PAGE_SIZE": 20, + "DEFAULT_FILTER_BACKENDS": ["django_filters.rest_framework.DjangoFilterBackend"], + "DEFAULT_METADATA_CLASS": "bothub.api.v1.metadata.Metadata", } @@ -188,95 +177,88 @@ # mail -envvar_EMAIL_HOST = env.str('EMAIL_HOST') +envvar_EMAIL_HOST = env.str("EMAIL_HOST") -ADMINS = env.list('ADMINS') -EMAIL_SUBJECT_PREFIX = '[bothub] ' -DEFAULT_FROM_EMAIL = env.str('DEFAULT_FROM_EMAIL') -SERVER_EMAIL = env.str('SERVER_EMAIL') +ADMINS = env.list("ADMINS") +EMAIL_SUBJECT_PREFIX = "[bothub] " +DEFAULT_FROM_EMAIL = env.str("DEFAULT_FROM_EMAIL") +SERVER_EMAIL = env.str("SERVER_EMAIL") if envvar_EMAIL_HOST: EMAIL_HOST = envvar_EMAIL_HOST - EMAIL_PORT = env.int('EMAIL_PORT') - EMAIL_HOST_USER = env.str('EMAIL_HOST_USER') - EMAIL_HOST_PASSWORD = env.str('EMAIL_HOST_PASSWORD') - EMAIL_USE_SSL = env.bool('EMAIL_USE_SSL') - EMAIL_USE_TLS = env.bool('EMAIL_USE_TLS') + EMAIL_PORT = env.int("EMAIL_PORT") + EMAIL_HOST_USER = env.str("EMAIL_HOST_USER") + EMAIL_HOST_PASSWORD = env.str("EMAIL_HOST_PASSWORD") + EMAIL_USE_SSL = env.bool("EMAIL_USE_SSL") + EMAIL_USE_TLS = env.bool("EMAIL_USE_TLS") else: - EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' + EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend" -SEND_EMAILS = env.bool('SEND_EMAILS') +SEND_EMAILS = env.bool("SEND_EMAILS") # webapp -BOTHUB_WEBAPP_BASE_URL = env.str('BOTHUB_WEBAPP_BASE_URL') +BOTHUB_WEBAPP_BASE_URL = env.str("BOTHUB_WEBAPP_BASE_URL") # NLP -BOTHUB_NLP_BASE_URL = env.str('BOTHUB_NLP_BASE_URL') +BOTHUB_NLP_BASE_URL = env.str("BOTHUB_NLP_BASE_URL") # CSRF -CSRF_COOKIE_DOMAIN = env.str('CSRF_COOKIE_DOMAIN') +CSRF_COOKIE_DOMAIN = env.str("CSRF_COOKIE_DOMAIN") -CSRF_COOKIE_SECURE = env.bool('CSRF_COOKIE_SECURE') +CSRF_COOKIE_SECURE = env.bool("CSRF_COOKIE_SECURE") # Logging LOGGING = DEFAULT_LOGGING -LOGGING['formatters']['bothub.health'] = { - 'format': '[bothub.health] {message}', - 'style': '{', +LOGGING["formatters"]["bothub.health"] = { + "format": "[bothub.health] {message}", + "style": "{", } -LOGGING['handlers']['bothub.health'] = { - 'level': 'DEBUG', - 'class': 'logging.StreamHandler', - 'formatter': 'bothub.health', +LOGGING["handlers"]["bothub.health"] = { + "level": "DEBUG", + "class": "logging.StreamHandler", + "formatter": "bothub.health", } -LOGGING['loggers']['bothub.health.checks'] = { - 'handlers': ['bothub.health'], - 'level': 'DEBUG', +LOGGING["loggers"]["bothub.health.checks"] = { + "handlers": ["bothub.health"], + "level": "DEBUG", } # Supported Languages SUPPORTED_LANGUAGES = env.get_value( - 'SUPPORTED_LANGUAGES', - cast_supported_languages, - 'en|pt', - True + "SUPPORTED_LANGUAGES", cast_supported_languages, "en|pt", True ) # SECURE PROXY SSL HEADER -SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https') +SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https") # Swagger SWAGGER_SETTINGS = { - 'USE_SESSION_AUTH': False, - 'DOC_EXPANSION': 'list', - 'APIS_SORTER': 'alpha', - 'SECURITY_DEFINITIONS': { - 'api_key': { - 'type': 'apiKey', - 'name': 'Authorization', - 'in': 'header' - }, + "USE_SESSION_AUTH": False, + "DOC_EXPANSION": "list", + "APIS_SORTER": "alpha", + "SECURITY_DEFINITIONS": { + "api_key": {"type": "apiKey", "name": "Authorization", "in": "header"} }, } # AWS -AWS_ACCESS_KEY_ID = env.str('BOTHUB_ENGINE_AWS_ACCESS_KEY_ID') -AWS_SECRET_ACCESS_KEY = env.str('BOTHUB_ENGINE_AWS_SECRET_ACCESS_KEY') -AWS_BUCKET_NAME = env.str('BOTHUB_ENGINE_AWS_S3_BUCKET_NAME') -AWS_REGION_NAME = env.str('BOTHUB_ENGINE_AWS_REGION_NAME') +AWS_ACCESS_KEY_ID = env.str("BOTHUB_ENGINE_AWS_ACCESS_KEY_ID") +AWS_SECRET_ACCESS_KEY = env.str("BOTHUB_ENGINE_AWS_SECRET_ACCESS_KEY") +AWS_BUCKET_NAME = env.str("BOTHUB_ENGINE_AWS_S3_BUCKET_NAME") +AWS_REGION_NAME = env.str("BOTHUB_ENGINE_AWS_REGION_NAME") diff --git a/bothub/urls.py b/bothub/urls.py index 028124d4..ee21015f 100644 --- a/bothub/urls.py +++ b/bothub/urls.py @@ -14,77 +14,93 @@ schema_view = get_schema_view( - openapi.Info( - title='API Documentation', - default_version='v1.0.1', - description='Documentation', - terms_of_service='https://www.google.com/policies/terms/', - contact=openapi.Contact(email='bothub@ilhasoft.com.br'), - license=openapi.License(name='GPL-3.0'), - ), - public=True, - permission_classes=[permissions.AllowAny], + openapi.Info( + title="API Documentation", + default_version="v1.0.1", + description="Documentation", + terms_of_service="https://www.google.com/policies/terms/", + contact=openapi.Contact(email="bothub@ilhasoft.com.br"), + license=openapi.License(name="GPL-3.0"), + ), + public=True, + permission_classes=[permissions.AllowAny], ) urlpatterns = [ - path('', schema_view.with_ui('swagger')), - path('v1/', include(bothub_api_routers.urls)), - path('v2/', include(bothub_api_v2_urls)), - path('admin/', admin.site.urls), - path('ping/', ping, name='ping'), - path('200/', r200, name='200'), + path("", schema_view.with_ui("swagger")), + path("v1/", include(bothub_api_routers.urls)), + path("v2/", include(bothub_api_v2_urls)), + path("admin/", admin.site.urls), + path("ping/", ping, name="ping"), + path("200/", r200, name="200"), path( - 'downloadbotdata//', - download_bot_data, - name='download_bot_data') + "downloadbotdata//", download_bot_data, name="download_bot_data" + ), ] if settings.DEBUG: + def render_template(template_name, **kwargs): def wrapper(request): from django.shortcuts import render + return render(request, template_name, kwargs) + return wrapper urlpatterns += [ - path('emails/', include([ - path( - 'welcome/', - render_template( - 'authentication/emails/welcome.html', - name='User')), - path( - 'new-role/', - render_template( - 'common/emails/new_role.html', - responsible_name='User', - user_name='Michael', - repository_name='Repository 1', - repository_url='http://localhost:8080/user/repo1/', - new_role='Admin')), - path( - 'new-request/', - render_template( - 'common/emails/new_request.html', - user_name='Michael', - repository_name='Repository 1', - text='Lorem ipsum dolor sit amet, consectetur ' + - 'adipiscing elit. Pellentesque tristique dapibus ' + - 'consectetur. Praesent eleifend sit amet nulla sed ' + - 'egestas. Nam ac quam lacus. Pellentesque posuere, ' + - 'nisl nullam.', - repository_url='http://localhost:8080/user/repo1/')), - path( - 'request-rejected/', - render_template( - 'common/emails/request_rejected.html', - repository_name='Repository 1')), - path( - 'request-approved/', - render_template( - 'common/emails/request_approved.html', - admin_name='User', - repository_name='Repository 1', - repository_url='http://localhost:8080/user/repo1/')), - ])), + path( + "emails/", + include( + [ + path( + "welcome/", + render_template( + "authentication/emails/welcome.html", name="User" + ), + ), + path( + "new-role/", + render_template( + "common/emails/new_role.html", + responsible_name="User", + user_name="Michael", + repository_name="Repository 1", + repository_url="http://localhost:8080/user/repo1/", + new_role="Admin", + ), + ), + path( + "new-request/", + render_template( + "common/emails/new_request.html", + user_name="Michael", + repository_name="Repository 1", + text="Lorem ipsum dolor sit amet, consectetur " + + "adipiscing elit. Pellentesque tristique dapibus " + + "consectetur. Praesent eleifend sit amet nulla sed " + + "egestas. Nam ac quam lacus. Pellentesque posuere, " + + "nisl nullam.", + repository_url="http://localhost:8080/user/repo1/", + ), + ), + path( + "request-rejected/", + render_template( + "common/emails/request_rejected.html", + repository_name="Repository 1", + ), + ), + path( + "request-approved/", + render_template( + "common/emails/request_approved.html", + admin_name="User", + repository_name="Repository 1", + repository_url="http://localhost:8080/user/repo1/", + ), + ), + ] + ), + ) ] diff --git a/bothub/utils.py b/bothub/utils.py index 4f0e2259..15bd9c9a 100644 --- a/bothub/utils.py +++ b/bothub/utils.py @@ -7,10 +7,7 @@ def cast_supported_languages(i): - return OrderedDict([ - x.split(':', 1) if ':' in x else (x, x) for x in - i.split('|') - ]) + return OrderedDict([x.split(":", 1) if ":" in x else (x, x) for x in i.split("|")]) def cast_empty_str_to_none(value): @@ -18,17 +15,21 @@ def cast_empty_str_to_none(value): def send_bot_data_file_aws(id, bot_data): - confmat_url = '' + confmat_url = "" - if all([settings.AWS_ACCESS_KEY_ID, settings.AWS_SECRET_ACCESS_KEY, - settings.AWS_BUCKET_NAME]): - confmat_filename = \ - f'repository_{str(id)}/bot_data_{uuid.uuid4()}.tar.gz' + if all( + [ + settings.AWS_ACCESS_KEY_ID, + settings.AWS_SECRET_ACCESS_KEY, + settings.AWS_BUCKET_NAME, + ] + ): + confmat_filename = f"repository_{str(id)}/bot_data_{uuid.uuid4()}.tar.gz" botdata = io.BytesIO(bot_data) s3_client = boto3.client( - 's3', + "s3", aws_access_key_id=settings.AWS_ACCESS_KEY_ID, aws_secret_access_key=settings.AWS_SECRET_ACCESS_KEY, region_name=settings.AWS_REGION_NAME, @@ -38,12 +39,10 @@ def send_bot_data_file_aws(id, bot_data): botdata, settings.AWS_BUCKET_NAME, confmat_filename, - ExtraArgs={'ContentType': 'application/gzip'} + ExtraArgs={"ContentType": "application/gzip"}, ) - confmat_url = '{}/{}/{}'.format( - s3_client.meta.endpoint_url, - settings.AWS_BUCKET_NAME, - confmat_filename + confmat_url = "{}/{}/{}".format( + s3_client.meta.endpoint_url, settings.AWS_BUCKET_NAME, confmat_filename ) except ClientError as e: print(e) From c4603eadaf97963f14269459522aff3e8287d862 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Tue, 1 Oct 2019 10:58:06 -0300 Subject: [PATCH 175/207] [fix] flake8 --- .flake8 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.flake8 b/.flake8 index 7594c5e1..b490946c 100644 --- a/.flake8 +++ b/.flake8 @@ -1,6 +1,7 @@ [flake8] max-line-length = 119 +ignore = E501,W503,E203 exclude = ./env migrations - ./manage.py \ No newline at end of file + ./manage.py From 77e7d1bd2ae0e4501f39f5ea12e1eadabf17ffbd Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Tue, 1 Oct 2019 16:06:06 -0300 Subject: [PATCH 176/207] Updated PEP8 --- bothub/api/v2/nlp/views.py | 48 +++++++++---------- .../migrations/0035_auto_20190902_1455.py | 15 +++--- bothub/common/models.py | 14 ++---- bothub/settings.py | 20 ++++---- 4 files changed, 41 insertions(+), 56 deletions(-) diff --git a/bothub/api/v2/nlp/views.py b/bothub/api/v2/nlp/views.py index 919a992b..2a2bd768 100644 --- a/bothub/api/v2/nlp/views.py +++ b/bothub/api/v2/nlp/views.py @@ -421,43 +421,39 @@ def retrieve(self, request, *args, **kwargs): update = self.get_object() regex = re.compile( - r'^(?:http|ftp)s?://' # http:// or https:// - r'(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+(?:[A-Z]{2,6}\.?|' - r'[A-Z0-9-]{2,}\.?)|' - r'localhost|' - r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})' - r'(?::\d+)?' - r'(?:/?|[/?]\S+)$', re.IGNORECASE) + r"^(?:http|ftp)s?://" # http:// or https:// + r"(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+(?:[A-Z]{2,6}\.?|" + r"[A-Z0-9-]{2,}\.?)|" + r"localhost|" + r"\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})" + r"(?::\d+)?" + r"(?:/?|[/?]\S+)$", + re.IGNORECASE, + ) if re.match(regex, update.bot_data) is not None: try: download = requests.get(update.bot_data) bot_data = base64.b64encode(download.content) except Exception: - bot_data = b'' + bot_data = b"" else: bot_data = update.bot_data - return Response({ - 'update_id': update.id, - 'repository_uuid': update.repository.uuid, - 'bot_data': str(bot_data) - }) + return Response( + { + "update_id": update.id, + "repository_uuid": update.repository.uuid, + "bot_data": str(bot_data), + } + ) def create(self, request, *args, **kwargs): check_auth(request) - id = request.data.get('id') - repository = get_object_or_404( - RepositoryUpdate, - pk=id - ) + id = request.data.get("id") + repository = get_object_or_404(RepositoryUpdate, pk=id) if settings.AWS_SEND: - bot_data = base64.b64decode(request.data.get('bot_data')) - repository.save_training( - send_bot_data_file_aws( - id, - bot_data - ) - ) + bot_data = base64.b64decode(request.data.get("bot_data")) + repository.save_training(send_bot_data_file_aws(id, bot_data)) else: - repository.save_training(request.data.get('bot_data')) + repository.save_training(request.data.get("bot_data")) return Response({}) diff --git a/bothub/common/migrations/0035_auto_20190902_1455.py b/bothub/common/migrations/0035_auto_20190902_1455.py index 2afd01c5..7013dc16 100644 --- a/bothub/common/migrations/0035_auto_20190902_1455.py +++ b/bothub/common/migrations/0035_auto_20190902_1455.py @@ -7,15 +7,12 @@ def update_repository(apps, schema_editor): if settings.AWS_SEND: - for update in RepositoryUpdate.objects.all().exclude(bot_data__exact=''): + for update in RepositoryUpdate.objects.all().exclude(bot_data__exact=""): repository_update = RepositoryUpdate.objects.get(pk=update.pk) bot_data = send_bot_data_file_aws(update.pk, update.bot_data) repository_update.bot_data = bot_data - repository_update.save( - update_fields=[ - 'bot_data', - ]) - print('Updating bot_data repository_update {}'.format(str(update.pk))) + repository_update.save(update_fields=["bot_data"]) + print("Updating bot_data repository_update {}".format(str(update.pk))) class Migration(migrations.Migration): @@ -25,8 +22,8 @@ class Migration(migrations.Migration): operations = [ migrations.RunPython(update_repository), migrations.AlterField( - model_name='repositoryupdate', - name='bot_data', - field=models.TextField(blank=True, verbose_name='bot data'), + model_name="repositoryupdate", + name="bot_data", + field=models.TextField(blank=True, verbose_name="bot data"), ), ] diff --git a/bothub/common/models.py b/bothub/common/models.py index 1ec118ae..4bbd0631 100644 --- a/bothub/common/models.py +++ b/bothub/common/models.py @@ -452,17 +452,9 @@ class Meta: ) use_competing_intents = models.BooleanField(default=False) use_name_entities = models.BooleanField(default=False) - created_at = models.DateTimeField( - _('created at'), - auto_now_add=True) - bot_data = models.TextField( - _('bot data'), - blank=True) - by = models.ForeignKey( - User, - models.CASCADE, - blank=True, - null=True) + created_at = models.DateTimeField(_("created at"), auto_now_add=True) + bot_data = models.TextField(_("bot data"), blank=True) + by = models.ForeignKey(User, models.CASCADE, blank=True, null=True) training_started_at = models.DateTimeField( _("training started at"), blank=True, null=True ) diff --git a/bothub/settings.py b/bothub/settings.py index b89ff6a3..0603f7a8 100644 --- a/bothub/settings.py +++ b/bothub/settings.py @@ -40,11 +40,11 @@ CSRF_COOKIE_SECURE=(bool, False), SUPPORTED_LANGUAGES=(cast_supported_languages, "en|pt"), CHECK_ACCESSIBLE_API_URL=(str, None), - BOTHUB_ENGINE_AWS_ACCESS_KEY_ID=(str, ''), - BOTHUB_ENGINE_AWS_SECRET_ACCESS_KEY=(str, ''), - BOTHUB_ENGINE_AWS_S3_BUCKET_NAME=(str, ''), - BOTHUB_ENGINE_AWS_REGION_NAME=(str, 'us-east-1'), - BOTHUB_ENGINE_AWS_SEND=(bool, False) + BOTHUB_ENGINE_AWS_ACCESS_KEY_ID=(str, ""), + BOTHUB_ENGINE_AWS_SECRET_ACCESS_KEY=(str, ""), + BOTHUB_ENGINE_AWS_S3_BUCKET_NAME=(str, ""), + BOTHUB_ENGINE_AWS_REGION_NAME=(str, "us-east-1"), + BOTHUB_ENGINE_AWS_SEND=(bool, False), ) # Build paths inside the project like this: os.path.join(BASE_DIR, ...) @@ -258,8 +258,8 @@ # AWS -AWS_SEND = env.bool('BOTHUB_ENGINE_AWS_SEND') -AWS_ACCESS_KEY_ID = env.str('BOTHUB_ENGINE_AWS_ACCESS_KEY_ID') -AWS_SECRET_ACCESS_KEY = env.str('BOTHUB_ENGINE_AWS_SECRET_ACCESS_KEY') -AWS_BUCKET_NAME = env.str('BOTHUB_ENGINE_AWS_S3_BUCKET_NAME') -AWS_REGION_NAME = env.str('BOTHUB_ENGINE_AWS_REGION_NAME') +AWS_SEND = env.bool("BOTHUB_ENGINE_AWS_SEND") +AWS_ACCESS_KEY_ID = env.str("BOTHUB_ENGINE_AWS_ACCESS_KEY_ID") +AWS_SECRET_ACCESS_KEY = env.str("BOTHUB_ENGINE_AWS_SECRET_ACCESS_KEY") +AWS_BUCKET_NAME = env.str("BOTHUB_ENGINE_AWS_S3_BUCKET_NAME") +AWS_REGION_NAME = env.str("BOTHUB_ENGINE_AWS_REGION_NAME") From 1a5290d98e17314b12d7cca97fcb564265b7525a Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Tue, 8 Oct 2019 08:56:47 -0300 Subject: [PATCH 177/207] Update Regex check url AWS --- Pipfile | 1 + Pipfile.lock | 60 +++++++++++++++++++++++--------------- bothub/api/v2/nlp/views.py | 15 ++-------- 3 files changed, 40 insertions(+), 36 deletions(-) diff --git a/Pipfile b/Pipfile index 9e440481..b55d0cf7 100644 --- a/Pipfile +++ b/Pipfile @@ -18,6 +18,7 @@ gevent = "*" packaging = "*" django-environ = "*" boto3 = "*" +validators = "*" [dev-packages] "flake8" = "*" diff --git a/Pipfile.lock b/Pipfile.lock index 574674e8..f0e81cc2 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "de9033e279afa3aa5dfb7a263f9e5b855543712b0cd5a20abd1cba5a45564dd6" + "sha256": "622a8920b1d5ef6db53fa5e8b3ab4b27b7c1b422d32d79624604ae0d12d23ba2" }, "pipfile-spec": 6, "requires": { @@ -18,18 +18,18 @@ "default": { "boto3": { "hashes": [ - "sha256:5ff78c697d8009b9fe9808baea60660f0a07be666fb7c65fc4c11756f568124e", - "sha256:d01314496080ac82ddff3d1b2c6ad542d89bfcb100b7a0e8aaf2d6aef99775c6" + "sha256:2efd0a9647ef8fd7bf9fbbfdeb77007050258aa39914569c689bdf9cc288cdc1", + "sha256:331b82e878f524be11c10d866a68b123b1c5e892d218a8250de10bf11cb14402" ], "index": "pypi", - "version": "==1.9.239" + "version": "==1.9.244" }, "botocore": { "hashes": [ - "sha256:14ff881779776a5b08e4bb8d7e0cd6ca86e36fc80decc536d605c406fb81c993", - "sha256:5df4a8f8bb579daed58368d6c15cdd72455bfee7dc86be243e2ef4dff5ba1177" + "sha256:7b75482156ef93e7a463f80411dc76fc868cd9fb1dedf03250cec98f8459d765", + "sha256:e43e7d19f203d572f78c18a6a16cb87bbea10bc0543e0285f7b6a35d0c825bb6" ], - "version": "==1.12.239" + "version": "==1.12.244" }, "certifi": { "hashes": [ @@ -60,6 +60,13 @@ ], "version": "==0.0.4" }, + "decorator": { + "hashes": [ + "sha256:86156361c50488b84a3f148056ea716ca587df2f0de1d34750d35c21312725de", + "sha256:f069f3a01830ca754ba5258fde2278454a0b5b79e0d7f5c13b3b97e57d4acff6" + ], + "version": "==4.4.0" + }, "django": { "hashes": [ "sha256:1a41831eace203fd1939edf899e07d7abd12ce9bafc3d9a5a63a24a8d1d12bd5", @@ -110,11 +117,11 @@ }, "drf-yasg": { "hashes": [ - "sha256:68fded2ffdf46e03f33e766184b7d8f1e1a5236f94acfd0c4ba932a57b812566", - "sha256:fcef74709ead2b365410be3d12afbfd0a6e49d1efe615a15a929da7e950bb83c" + "sha256:4cfec631880ae527a91ec7cd3241aea2f82189f59e2f089119aa687761afb227", + "sha256:504cce09035cf1bace63b84d9d778b772f86bb37d8a71ed6f723346362e633b2" ], "index": "pypi", - "version": "==1.16.1" + "version": "==1.17.0" }, "gevent": { "hashes": [ @@ -199,10 +206,10 @@ }, "jinja2": { "hashes": [ - "sha256:065c4f02ebe7f7cf559e49ee5a95fb800a9e4528727aec6f24402a5374c65013", - "sha256:14dd6caf1527abb21f08f86c784eac40853ba93edb79552aa1e4b8aef1b61c7b" + "sha256:74320bb91f31270f9551d46522e33af46a80c3d619f4a4bf42b3164d30b5911f", + "sha256:9fe95f19286cfefaa917656583d020be14e7859c6b0252588391e47db34527de" ], - "version": "==2.10.1" + "version": "==2.10.3" }, "jmespath": { "hashes": [ @@ -344,6 +351,13 @@ "markers": "python_version >= '3.4'", "version": "==1.24.3" }, + "validators": { + "hashes": [ + "sha256:f0ac832212e3ee2e9b10e156f19b106888cf1429c291fbc5297aae87685014ae" + ], + "index": "pypi", + "version": "==0.14.0" + }, "whitenoise": { "hashes": [ "sha256:118ab3e5f815d380171b100b05b76de2a07612f422368a201a9ffdeefb2251c1", @@ -371,10 +385,10 @@ }, "attrs": { "hashes": [ - "sha256:69c0dbf2ed392de1cb5ec704444b08a5ef81680a61cb899dc08127123af36a79", - "sha256:f0b870f674851ecbfbbbd364d6b5cbdff9dcedbc7f3f5e18a6891057f21fe399" + "sha256:ec20e7a4825331c1b5ebf261d111e16fa9612c1f7a5e1f884f12bd53a664dfd2", + "sha256:f913492e1663d3c36f502e5e9ba6cd13cf19d7fab50aa13239e420fef95e1396" ], - "version": "==19.1.0" + "version": "==19.2.0" }, "autopep8": { "hashes": [ @@ -518,11 +532,11 @@ }, "prompt-toolkit": { "hashes": [ - "sha256:11adf3389a996a6d45cc277580d0d53e8a5afd281d0c9ec71b28e6f121463780", - "sha256:2519ad1d8038fd5fc8e770362237ad0364d16a7650fb5724af6997ed5515e3c1", - "sha256:977c6583ae813a37dc1c2e1b715892461fcbdaa57f6fc62f33a528c4886c8f55" + "sha256:46642344ce457641f28fc9d1c9ca939b63dadf8df128b86f1b9860e59c73a5e4", + "sha256:e7f8af9e3d70f514373bf41aa51bc33af12a6db3f71461ea47fea985defb2c31", + "sha256:f15af68f66e664eaa559d4ac8a928111eebd5feda0c11738b5998045224829db" ], - "version": "==2.0.9" + "version": "==2.0.10" }, "ptyprocess": { "hashes": [ @@ -568,10 +582,10 @@ }, "traitlets": { "hashes": [ - "sha256:9c4bd2d267b7153df9152698efb1050a5d84982d3384a37b2c1f7723ba3e7835", - "sha256:c6cb5e6f57c5a9bdaa40fa71ce7b4af30298fbab9ece9815b5d995ab6217c7d9" + "sha256:70b4c6a1d9019d7b4f6846832288f86998aa3b9207c6821f3578a6a6a467fe44", + "sha256:d023ee369ddd2763310e4c3eae1ff649689440d4ae59d7485eb4cfbbe3e359f7" ], - "version": "==4.3.2" + "version": "==4.3.3" }, "wcwidth": { "hashes": [ diff --git a/bothub/api/v2/nlp/views.py b/bothub/api/v2/nlp/views.py index 2a2bd768..b0090355 100644 --- a/bothub/api/v2/nlp/views.py +++ b/bothub/api/v2/nlp/views.py @@ -1,7 +1,7 @@ import base64 import json -import re import requests +import validators from django.conf import settings from django.db import models @@ -420,18 +420,7 @@ def retrieve(self, request, *args, **kwargs): check_auth(request) update = self.get_object() - regex = re.compile( - r"^(?:http|ftp)s?://" # http:// or https:// - r"(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+(?:[A-Z]{2,6}\.?|" - r"[A-Z0-9-]{2,}\.?)|" - r"localhost|" - r"\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})" - r"(?::\d+)?" - r"(?:/?|[/?]\S+)$", - re.IGNORECASE, - ) - - if re.match(regex, update.bot_data) is not None: + if validators.url(str(update.bot_data).lower()): try: download = requests.get(update.bot_data) bot_data = base64.b64encode(download.content) From 943ff68e2cca6b77ad732e4f6282c9c3c3f6339e Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Tue, 8 Oct 2019 09:09:13 -0300 Subject: [PATCH 178/207] Updated Check URL --- Pipfile | 1 - Pipfile.lock | 16 +--------------- bothub/api/v2/nlp/views.py | 13 +++++++++++-- 3 files changed, 12 insertions(+), 18 deletions(-) diff --git a/Pipfile b/Pipfile index b55d0cf7..9e440481 100644 --- a/Pipfile +++ b/Pipfile @@ -18,7 +18,6 @@ gevent = "*" packaging = "*" django-environ = "*" boto3 = "*" -validators = "*" [dev-packages] "flake8" = "*" diff --git a/Pipfile.lock b/Pipfile.lock index f0e81cc2..4bf45f76 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "622a8920b1d5ef6db53fa5e8b3ab4b27b7c1b422d32d79624604ae0d12d23ba2" + "sha256": "de9033e279afa3aa5dfb7a263f9e5b855543712b0cd5a20abd1cba5a45564dd6" }, "pipfile-spec": 6, "requires": { @@ -60,13 +60,6 @@ ], "version": "==0.0.4" }, - "decorator": { - "hashes": [ - "sha256:86156361c50488b84a3f148056ea716ca587df2f0de1d34750d35c21312725de", - "sha256:f069f3a01830ca754ba5258fde2278454a0b5b79e0d7f5c13b3b97e57d4acff6" - ], - "version": "==4.4.0" - }, "django": { "hashes": [ "sha256:1a41831eace203fd1939edf899e07d7abd12ce9bafc3d9a5a63a24a8d1d12bd5", @@ -351,13 +344,6 @@ "markers": "python_version >= '3.4'", "version": "==1.24.3" }, - "validators": { - "hashes": [ - "sha256:f0ac832212e3ee2e9b10e156f19b106888cf1429c291fbc5297aae87685014ae" - ], - "index": "pypi", - "version": "==0.14.0" - }, "whitenoise": { "hashes": [ "sha256:118ab3e5f815d380171b100b05b76de2a07612f422368a201a9ffdeefb2251c1", diff --git a/bothub/api/v2/nlp/views.py b/bothub/api/v2/nlp/views.py index b0090355..fc4fa9ce 100644 --- a/bothub/api/v2/nlp/views.py +++ b/bothub/api/v2/nlp/views.py @@ -1,12 +1,13 @@ import base64 import json import requests -import validators from django.conf import settings from django.db import models from django.utils.translation import gettext_lazy as _ from django.shortcuts import get_object_or_404 +from django.core.validators import URLValidator +from django.core.exceptions import ValidationError from rest_framework import mixins from rest_framework import exceptions @@ -420,7 +421,15 @@ def retrieve(self, request, *args, **kwargs): check_auth(request) update = self.get_object() - if validators.url(str(update.bot_data).lower()): + validator = URLValidator() + + try: + validator(str(update.bot_data)) + url_valid = True + except ValidationError: + url_valid = False + + if url_valid: try: download = requests.get(update.bot_data) bot_data = base64.b64encode(download.content) From 4409b7bd2766640f4062490473cd4854c7303f63 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Tue, 8 Oct 2019 09:15:53 -0300 Subject: [PATCH 179/207] Update Check URL --- bothub/api/v2/nlp/views.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/bothub/api/v2/nlp/views.py b/bothub/api/v2/nlp/views.py index fc4fa9ce..925d7d31 100644 --- a/bothub/api/v2/nlp/views.py +++ b/bothub/api/v2/nlp/views.py @@ -425,18 +425,14 @@ def retrieve(self, request, *args, **kwargs): try: validator(str(update.bot_data)) - url_valid = True - except ValidationError: - url_valid = False - - if url_valid: try: download = requests.get(update.bot_data) bot_data = base64.b64encode(download.content) except Exception: bot_data = b"" - else: + except ValidationError: bot_data = update.bot_data + return Response( { "update_id": update.id, From fa7c8b4553cd7d4810b9f327d1d8f37138edfcc8 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Tue, 8 Oct 2019 09:18:01 -0300 Subject: [PATCH 180/207] Updated Check URL --- bothub/api/v2/nlp/views.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/bothub/api/v2/nlp/views.py b/bothub/api/v2/nlp/views.py index 925d7d31..1007317f 100644 --- a/bothub/api/v2/nlp/views.py +++ b/bothub/api/v2/nlp/views.py @@ -425,13 +425,12 @@ def retrieve(self, request, *args, **kwargs): try: validator(str(update.bot_data)) - try: - download = requests.get(update.bot_data) - bot_data = base64.b64encode(download.content) - except Exception: - bot_data = b"" + download = requests.get(update.bot_data) + bot_data = base64.b64encode(download.content) except ValidationError: bot_data = update.bot_data + except Exception: + bot_data = b"" return Response( { From 5bc7bd75bfe0518a3dd2a7e7b4803e42de11c37a Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Mon, 14 Oct 2019 10:14:37 -0300 Subject: [PATCH 181/207] [fix] Migrations --- .../0032_repository_total_updates.py | 27 -------- .../migrations/0033_auto_20190816_2030.py | 21 ------- .../migrations/0034_repository_nlp_server.py | 16 ----- .../migrations/0035_auto_20190902_1455.py | 29 --------- .../migrations/0037_auto_20191011_2021.py | 61 +++++++++++++++++++ bothub/common/models.py | 2 +- 6 files changed, 62 insertions(+), 94 deletions(-) delete mode 100644 bothub/common/migrations/0032_repository_total_updates.py delete mode 100644 bothub/common/migrations/0033_auto_20190816_2030.py delete mode 100644 bothub/common/migrations/0034_repository_nlp_server.py delete mode 100644 bothub/common/migrations/0035_auto_20190902_1455.py create mode 100644 bothub/common/migrations/0037_auto_20191011_2021.py diff --git a/bothub/common/migrations/0032_repository_total_updates.py b/bothub/common/migrations/0032_repository_total_updates.py deleted file mode 100644 index e57dd2de..00000000 --- a/bothub/common/migrations/0032_repository_total_updates.py +++ /dev/null @@ -1,27 +0,0 @@ -# Generated by Django 2.1.5 on 2019-08-14 19:45 - -from django.db import migrations, models - -from bothub.common.models import RepositoryUpdate -from bothub.common.models import Repository - - -def updateRepository(apps, schema_editor): - for update in RepositoryUpdate.objects.all().filter(trained_at__isnull=False): - repository = Repository.objects.get(uuid=update.repository.uuid) - repository.total_updates += 1 - repository.save() - - -class Migration(migrations.Migration): - - dependencies = [("common", "0031_auto_20190502_1732")] - - operations = [ - migrations.AddField( - model_name="repository", - name="total_updates", - field=models.IntegerField(default=0, verbose_name="total updates"), - ), - migrations.RunPython(updateRepository), - ] diff --git a/bothub/common/migrations/0033_auto_20190816_2030.py b/bothub/common/migrations/0033_auto_20190816_2030.py deleted file mode 100644 index 2f26debe..00000000 --- a/bothub/common/migrations/0033_auto_20190816_2030.py +++ /dev/null @@ -1,21 +0,0 @@ -# Generated by Django 2.1.5 on 2019-08-16 20:30 - -from django.db import migrations, models -import django.utils.timezone - - -class Migration(migrations.Migration): - - dependencies = [("common", "0032_repository_total_updates")] - - operations = [ - migrations.RemoveField(model_name="repositoryvote", name="vote"), - migrations.AddField( - model_name="repositoryvote", - name="created", - field=models.DateTimeField( - auto_now_add=True, default=django.utils.timezone.now - ), - preserve_default=False, - ), - ] diff --git a/bothub/common/migrations/0034_repository_nlp_server.py b/bothub/common/migrations/0034_repository_nlp_server.py deleted file mode 100644 index 8c6ef05f..00000000 --- a/bothub/common/migrations/0034_repository_nlp_server.py +++ /dev/null @@ -1,16 +0,0 @@ -# Generated by Django 2.1.5 on 2019-08-30 17:57 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [("common", "0033_auto_20190816_2030")] - - operations = [ - migrations.AddField( - model_name="repository", - name="nlp_server", - field=models.URLField(blank=True, null=True, verbose_name="Base URL NLP"), - ) - ] diff --git a/bothub/common/migrations/0035_auto_20190902_1455.py b/bothub/common/migrations/0035_auto_20190902_1455.py deleted file mode 100644 index 7013dc16..00000000 --- a/bothub/common/migrations/0035_auto_20190902_1455.py +++ /dev/null @@ -1,29 +0,0 @@ -# Generated by Django 2.1.5 on 2019-09-02 14:55 -from django.conf import settings -from django.db import migrations, models -from bothub.utils import send_bot_data_file_aws -from bothub.common.models import RepositoryUpdate - - -def update_repository(apps, schema_editor): - if settings.AWS_SEND: - for update in RepositoryUpdate.objects.all().exclude(bot_data__exact=""): - repository_update = RepositoryUpdate.objects.get(pk=update.pk) - bot_data = send_bot_data_file_aws(update.pk, update.bot_data) - repository_update.bot_data = bot_data - repository_update.save(update_fields=["bot_data"]) - print("Updating bot_data repository_update {}".format(str(update.pk))) - - -class Migration(migrations.Migration): - - dependencies = [("common", "0034_repository_nlp_server")] - - operations = [ - migrations.RunPython(update_repository), - migrations.AlterField( - model_name="repositoryupdate", - name="bot_data", - field=models.TextField(blank=True, verbose_name="bot data"), - ), - ] diff --git a/bothub/common/migrations/0037_auto_20191011_2021.py b/bothub/common/migrations/0037_auto_20191011_2021.py new file mode 100644 index 00000000..aa7eb1ed --- /dev/null +++ b/bothub/common/migrations/0037_auto_20191011_2021.py @@ -0,0 +1,61 @@ +# Generated by Django 2.1.11 on 2019-10-11 20:21 + +import django.utils.timezone +from django.db import migrations, models +from django.conf import settings +from bothub.utils import send_bot_data_file_aws +from bothub.common.models import RepositoryUpdate +from bothub.common.models import Repository + + +def updateRepository(apps, schema_editor): + for update in RepositoryUpdate.objects.all().filter(trained_at__isnull=False): + repository = Repository.objects.get(uuid=update.repository.uuid) + repository.total_updates += 1 + repository.save() + + +def update_repository(apps, schema_editor): + if settings.AWS_SEND: + for update in RepositoryUpdate.objects.all().exclude(bot_data__exact=""): + repository_update = RepositoryUpdate.objects.get(pk=update.pk) + bot_data = send_bot_data_file_aws(update.pk, update.bot_data) + repository_update.bot_data = bot_data + repository_update.save(update_fields=["bot_data"]) + print("Updating bot_data repository_update {}".format(str(update.pk))) + + +class Migration(migrations.Migration): + + dependencies = [ + ('common', '0031_auto_20190502_1732'), + ] + + operations = [ + migrations.RemoveField( + model_name='repositoryvote', + name='vote', + ), + migrations.AddField( + model_name='repository', + name='nlp_server', + field=models.URLField(blank=True, null=True, verbose_name='Base URL NLP'), + ), + migrations.AddField( + model_name='repository', + name='total_updates', + field=models.IntegerField(default=0, verbose_name='total updates'), + ), + migrations.RunPython(updateRepository), + migrations.AddField( + model_name='repositoryvote', + name='created', + field=models.DateTimeField(default=django.utils.timezone.now, editable=False), + ), + migrations.RunPython(update_repository), + migrations.AlterField( + model_name='repositoryupdate', + name='bot_data', + field=models.TextField(blank=True, verbose_name='bot data'), + ), + ] diff --git a/bothub/common/models.py b/bothub/common/models.py index 4bbd0631..323a2e6d 100644 --- a/bothub/common/models.py +++ b/bothub/common/models.py @@ -1086,7 +1086,7 @@ class Meta: user = models.ForeignKey(User, models.CASCADE, related_name="repository_votes") repository = models.ForeignKey(Repository, models.CASCADE, related_name="votes") - created = models.DateTimeField(editable=False, auto_now_add=True) + created = models.DateTimeField(editable=False, default=timezone.now) class RequestRepositoryAuthorization(models.Model): From a4aafeb20216d821d45ce9edc7cb95779749789a Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Tue, 15 Oct 2019 09:28:37 -0300 Subject: [PATCH 182/207] [refact] Router Train NLP --- bothub/api/v2/nlp/views.py | 96 +++++++++++++------------- bothub/api/v2/tests/test_nlp.py | 116 -------------------------------- 2 files changed, 48 insertions(+), 164 deletions(-) diff --git a/bothub/api/v2/nlp/views.py b/bothub/api/v2/nlp/views.py index 1007317f..3f50e32b 100644 --- a/bothub/api/v2/nlp/views.py +++ b/bothub/api/v2/nlp/views.py @@ -106,62 +106,59 @@ def start_training(self, request, **kwargs): } ) - @action(detail=True, methods=["GET"], url_name="gettext", lookup_field=[]) - def get_text(self, request, **kwargs): + @action(detail=True, methods=["GET"], url_name="get_entities_and_labels", lookup_field=[]) + def get_entities_and_labels(self, request, **kwargs): check_auth(request) try: - update_id = int(request.query_params.get("update_id")) - example_id = int(request.query_params.get("example_id")) + examples = request.data.get('examples') + label_examples_query = request.data.get('label_examples_query') + update_id = request.data.get('update_id') except ValueError: raise exceptions.NotFound() - repository = get_object_or_404( - get_object_or_404(RepositoryUpdate, pk=update_id).examples, pk=example_id - ).get_text(request.query_params.get("language")) + repository_update = RepositoryUpdate.objects.get(pk=update_id) - return Response({"get_text": repository}) + examples_return = [] + label_examples = [] - @action(detail=True, methods=["GET"], url_name="get_entities", lookup_field=[]) - def get_entities(self, request, **kwargs): - check_auth(request) + for example in examples: + try: + repository = repository_update.examples.get(pk=example.get('example_id')) - try: - update_id = int(request.query_params.get("update_id")) - example_id = int(request.query_params.get("example_id")) - except ValueError: - raise exceptions.NotFound() + get_entities = repository.get_entities(request.query_params.get("language")) - repository = get_object_or_404( - get_object_or_404(RepositoryUpdate, pk=update_id).examples, pk=example_id - ).get_entities(request.query_params.get("language")) + get_text = repository.get_text(request.query_params.get("language")) - entities = [entit.rasa_nlu_data for entit in repository] + examples_return.append({ + 'text': get_text, + 'intent': example.get("example_intent"), + 'entities': [entit.rasa_nlu_data for entit in get_entities] + }) - return Response({"entities": entities}) + except Exception: + pass - @action( - detail=True, methods=["GET"], url_name="get_entities_label", lookup_field=[] - ) - def get_entities_label(self, request, **kwargs): - check_auth(request) + for example in label_examples_query: + try: + repository_examples = repository_update.examples.get(pk=example.get('example_id')) - try: - update_id = int(request.query_params.get("update_id")) - example_id = int(request.query_params.get("example_id")) - except ValueError: - raise exceptions.NotFound() + entities = [ + example_entity.get_rasa_nlu_data(label_as_entity=True) + for example_entity in filter( + lambda ee: ee.entity.label, + repository_examples.get_entities(request.query_params.get("language")) + ) + ] - repository = get_object_or_404( - get_object_or_404(RepositoryUpdate, pk=update_id).examples, pk=example_id - ).get_entities(request.query_params.get("language")) + label_examples.append({ + 'entities': entities, + 'text': repository_examples.get_text(request.query_params.get("language")) + }) + except Exception: + pass - entities = [ - example_entity.get_rasa_nlu_data(label_as_entity=True) - for example_entity in filter(lambda ee: ee.entity.label, repository) - ] - - return Response({"entities": entities}) + return Response({'examples': examples_return, 'label_examples': label_examples}) @action(detail=True, methods=["POST"], url_name="train_fail", lookup_field=[]) def train_fail(self, request, **kwargs): @@ -195,13 +192,16 @@ def retrieve(self, request, *args, **kwargs): update = repository.last_trained_update( str(request.query_params.get("language")) ) - return Response( - { - "update": False if update is None else True, - "update_id": update.id, - "language": update.language, - } - ) + try: + return Response( + { + "update": False if update is None else True, + "update_id": update.id, + "language": update.language, + } + ) + except Exception: + return Response({}, status=400) @action(detail=True, methods=["GET"], url_name="repository_entity", lookup_field=[]) def repository_entity(self, request, **kwargs): @@ -217,7 +217,7 @@ def repository_entity(self, request, **kwargs): return Response( { - "label": repository_entity.label, + "label": True if repository_entity.label else False, "label_value": repository_entity.label.value, } ) diff --git a/bothub/api/v2/tests/test_nlp.py b/bothub/api/v2/tests/test_nlp.py index c08cea3e..22769dff 100644 --- a/bothub/api/v2/tests/test_nlp.py +++ b/bothub/api/v2/tests/test_nlp.py @@ -66,122 +66,6 @@ def test_not_auth(self): self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED) -class TrainGetTextTestCase(TestCase): - def setUp(self): - self.factory = RequestFactory() - - self.owner, self.owner_token = create_user_and_token("owner") - self.user, self.user_token = create_user_and_token() - - self.repository = Repository.objects.create( - owner=self.owner, - name="Testing", - slug="test", - language=languages.LANGUAGE_EN, - ) - - self.repository_authorization = RepositoryAuthorization.objects.create( - user=self.user, repository=self.repository, role=3 - ) - - self.repository_update = RepositoryUpdate.objects.create( - repository=self.repository, - language=languages.LANGUAGE_EN, - algorithm="statistical_model", - ) - - self.repository_examples = RepositoryExample.objects.create( - repository_update=self.repository_update, text="hello", intent="greet" - ) - - def request(self, token): - authorization_header = {"HTTP_AUTHORIZATION": "Bearer {}".format(token)} - request = self.factory.get( - "/v2/repository/nlp/authorization/train/get_text/" - "?update_id={}&example_id={}&language={}".format( - self.repository_update.pk, - self.repository_examples.pk, - languages.LANGUAGE_EN, - ), - **authorization_header - ) - response = RepositoryAuthorizationTrainViewSet.as_view({"get": "get_text"})( - request - ) - response.render() - content_data = json.loads(response.content) - return (response, content_data) - - def test_ok(self): - response, content_data = self.request(str(self.repository_authorization.uuid)) - self.assertEqual(content_data.get("get_text"), "hello") - self.assertEqual(response.status_code, status.HTTP_200_OK) - - def test_not_auth(self): - response, content_data = self.request("NO-TOKEN") - self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED) - - -class TrainGetEntitiesTestCase(TestCase): - def setUp(self): - self.factory = RequestFactory() - - self.owner, self.owner_token = create_user_and_token("owner") - self.user, self.user_token = create_user_and_token() - - self.repository = Repository.objects.create( - owner=self.owner, - name="Testing", - slug="test", - language=languages.LANGUAGE_EN, - ) - - self.repository_authorization = RepositoryAuthorization.objects.create( - user=self.user, repository=self.repository, role=3 - ) - - self.repository_update = RepositoryUpdate.objects.create( - repository=self.repository, - language=languages.LANGUAGE_EN, - algorithm="statistical_model", - ) - - self.repository_examples = RepositoryExample.objects.create( - repository_update=self.repository_update, text="hello", intent="greet" - ) - - RepositoryExampleEntity.objects.create( - repository_example=self.repository_examples, start=11, end=18, entity="name" - ) - - def request(self, token): - authorization_header = {"HTTP_AUTHORIZATION": "Bearer {}".format(token)} - request = self.factory.get( - "/v2/repository/nlp/authorization/train/get_entities/" - "?update_id={}&example_id={}&language={}".format( - self.repository_update.pk, - self.repository_examples.pk, - languages.LANGUAGE_EN, - ), - **authorization_header - ) - response = RepositoryAuthorizationTrainViewSet.as_view({"get": "get_entities"})( - request - ) - response.render() - content_data = json.loads(response.content) - return (response, content_data) - - def test_ok(self): - response, content_data = self.request(str(self.repository_authorization.uuid)) - self.assertEqual(len(content_data.get("entities")), 1) - self.assertEqual(response.status_code, status.HTTP_200_OK) - - def test_not_auth(self): - response, content_data = self.request("NO-TOKEN") - self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED) - - class TrainFailTestCase(TestCase): def setUp(self): self.factory = RequestFactory() From 95deaf679dc462dab5e3f3d25e0a9592f9b8dcd0 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Tue, 15 Oct 2019 09:33:01 -0300 Subject: [PATCH 183/207] PEP8 Black --- bothub/api/v2/nlp/views.py | 55 +++++++++++++------ .../migrations/0037_auto_20191011_2021.py | 35 ++++++------ 2 files changed, 53 insertions(+), 37 deletions(-) diff --git a/bothub/api/v2/nlp/views.py b/bothub/api/v2/nlp/views.py index 3f50e32b..13db2e84 100644 --- a/bothub/api/v2/nlp/views.py +++ b/bothub/api/v2/nlp/views.py @@ -106,14 +106,19 @@ def start_training(self, request, **kwargs): } ) - @action(detail=True, methods=["GET"], url_name="get_entities_and_labels", lookup_field=[]) + @action( + detail=True, + methods=["GET"], + url_name="get_entities_and_labels", + lookup_field=[], + ) def get_entities_and_labels(self, request, **kwargs): check_auth(request) try: - examples = request.data.get('examples') - label_examples_query = request.data.get('label_examples_query') - update_id = request.data.get('update_id') + examples = request.data.get("examples") + label_examples_query = request.data.get("label_examples_query") + update_id = request.data.get("update_id") except ValueError: raise exceptions.NotFound() @@ -124,41 +129,55 @@ def get_entities_and_labels(self, request, **kwargs): for example in examples: try: - repository = repository_update.examples.get(pk=example.get('example_id')) + repository = repository_update.examples.get( + pk=example.get("example_id") + ) - get_entities = repository.get_entities(request.query_params.get("language")) + get_entities = repository.get_entities( + request.query_params.get("language") + ) get_text = repository.get_text(request.query_params.get("language")) - examples_return.append({ - 'text': get_text, - 'intent': example.get("example_intent"), - 'entities': [entit.rasa_nlu_data for entit in get_entities] - }) + examples_return.append( + { + "text": get_text, + "intent": example.get("example_intent"), + "entities": [entit.rasa_nlu_data for entit in get_entities], + } + ) except Exception: pass for example in label_examples_query: try: - repository_examples = repository_update.examples.get(pk=example.get('example_id')) + repository_examples = repository_update.examples.get( + pk=example.get("example_id") + ) entities = [ example_entity.get_rasa_nlu_data(label_as_entity=True) for example_entity in filter( lambda ee: ee.entity.label, - repository_examples.get_entities(request.query_params.get("language")) + repository_examples.get_entities( + request.query_params.get("language") + ), ) ] - label_examples.append({ - 'entities': entities, - 'text': repository_examples.get_text(request.query_params.get("language")) - }) + label_examples.append( + { + "entities": entities, + "text": repository_examples.get_text( + request.query_params.get("language") + ), + } + ) except Exception: pass - return Response({'examples': examples_return, 'label_examples': label_examples}) + return Response({"examples": examples_return, "label_examples": label_examples}) @action(detail=True, methods=["POST"], url_name="train_fail", lookup_field=[]) def train_fail(self, request, **kwargs): diff --git a/bothub/common/migrations/0037_auto_20191011_2021.py b/bothub/common/migrations/0037_auto_20191011_2021.py index aa7eb1ed..e43f6dbb 100644 --- a/bothub/common/migrations/0037_auto_20191011_2021.py +++ b/bothub/common/migrations/0037_auto_20191011_2021.py @@ -27,35 +27,32 @@ def update_repository(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ - ('common', '0031_auto_20190502_1732'), - ] + dependencies = [("common", "0031_auto_20190502_1732")] operations = [ - migrations.RemoveField( - model_name='repositoryvote', - name='vote', - ), + migrations.RemoveField(model_name="repositoryvote", name="vote"), migrations.AddField( - model_name='repository', - name='nlp_server', - field=models.URLField(blank=True, null=True, verbose_name='Base URL NLP'), + model_name="repository", + name="nlp_server", + field=models.URLField(blank=True, null=True, verbose_name="Base URL NLP"), ), migrations.AddField( - model_name='repository', - name='total_updates', - field=models.IntegerField(default=0, verbose_name='total updates'), + model_name="repository", + name="total_updates", + field=models.IntegerField(default=0, verbose_name="total updates"), ), migrations.RunPython(updateRepository), migrations.AddField( - model_name='repositoryvote', - name='created', - field=models.DateTimeField(default=django.utils.timezone.now, editable=False), + model_name="repositoryvote", + name="created", + field=models.DateTimeField( + default=django.utils.timezone.now, editable=False + ), ), migrations.RunPython(update_repository), migrations.AlterField( - model_name='repositoryupdate', - name='bot_data', - field=models.TextField(blank=True, verbose_name='bot data'), + model_name="repositoryupdate", + name="bot_data", + field=models.TextField(blank=True, verbose_name="bot data"), ), ] From 6b13ee087d1505c3f2f458948caa16aa92bc6335 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Fri, 18 Oct 2019 11:51:42 -0300 Subject: [PATCH 184/207] [fix] Profile User --- bothub/api/v2/account/views.py | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/bothub/api/v2/account/views.py b/bothub/api/v2/account/views.py index 211a2a3e..6887d11b 100644 --- a/bothub/api/v2/account/views.py +++ b/bothub/api/v2/account/views.py @@ -1,12 +1,15 @@ from django.utils.decorators import method_decorator from django_filters.rest_framework import DjangoFilterBackend from rest_framework.filters import SearchFilter +from rest_framework.generics import get_object_or_404 from rest_framework.viewsets import GenericViewSet from rest_framework.response import Response from rest_framework.authtoken.models import Token from rest_framework import status, mixins from rest_framework import permissions from drf_yasg.utils import swagger_auto_schema + +from bothub.api.v2 import WRITE_METHODS from bothub.api.v2.metadata import Metadata from bothub.authentication.models import User @@ -112,7 +115,10 @@ def create(self, request, *args, **kwargs): class UserProfileViewSet( - mixins.RetrieveModelMixin, mixins.UpdateModelMixin, GenericViewSet + mixins.ListModelMixin, + mixins.RetrieveModelMixin, + mixins.UpdateModelMixin, + GenericViewSet, ): """ Get user profile @@ -123,6 +129,24 @@ class UserProfileViewSet( lookup_field = "nickname" permission_classes = [permissions.IsAuthenticatedOrReadOnly] + def get_object(self, *args, **kwargs): + request = self.request + user = request.user + + if request.method in WRITE_METHODS: + # May raise a permission denied + self.check_object_permissions(self.request, user) + return user + return super().get_object(*args, **kwargs) + + def list(self, request, *args, **kwargs): + self.permission_classes = [permissions.IsAuthenticated] + self.lookup_field = None + serializer = self.get_serializer( + get_object_or_404(User, email=request.user), many=False + ) + return Response(serializer.data) + class SearchUserViewSet(mixins.ListModelMixin, GenericViewSet): serializer_class = UserSerializer From 26a757646d7a285a172e0722745922380d8e3631 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Fri, 18 Oct 2019 17:12:27 -0300 Subject: [PATCH 185/207] [fix] Router Profile --- bothub/api/v2/account/views.py | 61 +++++++++++++++++----------------- bothub/api/v2/routers.py | 2 ++ 2 files changed, 33 insertions(+), 30 deletions(-) diff --git a/bothub/api/v2/account/views.py b/bothub/api/v2/account/views.py index 6887d11b..a87ffbdc 100644 --- a/bothub/api/v2/account/views.py +++ b/bothub/api/v2/account/views.py @@ -1,24 +1,21 @@ from django.utils.decorators import method_decorator from django_filters.rest_framework import DjangoFilterBackend +from drf_yasg.utils import swagger_auto_schema +from rest_framework import permissions +from rest_framework import status, mixins +from rest_framework.authtoken.models import Token from rest_framework.filters import SearchFilter -from rest_framework.generics import get_object_or_404 -from rest_framework.viewsets import GenericViewSet from rest_framework.response import Response -from rest_framework.authtoken.models import Token -from rest_framework import status, mixins -from rest_framework import permissions -from drf_yasg.utils import swagger_auto_schema +from rest_framework.viewsets import GenericViewSet -from bothub.api.v2 import WRITE_METHODS from bothub.api.v2.metadata import Metadata from bothub.authentication.models import User - +from .serializers import ChangePasswordSerializer from .serializers import LoginSerializer from .serializers import RegisterUserSerializer -from .serializers import ChangePasswordSerializer from .serializers import RequestResetPasswordSerializer -from .serializers import UserSerializer from .serializers import ResetPasswordSerializer +from .serializers import UserSerializer @method_decorator( @@ -114,38 +111,42 @@ def create(self, request, *args, **kwargs): return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) -class UserProfileViewSet( - mixins.ListModelMixin, - mixins.RetrieveModelMixin, - mixins.UpdateModelMixin, - GenericViewSet, +class MyUserProfileViewSet( + mixins.RetrieveModelMixin, mixins.UpdateModelMixin, GenericViewSet ): """ - Get user profile + Manager current user profile. + retrieve: + Get current user profile + update: + Update current user profile. + partial_update: + Update, partially, current user profile. """ serializer_class = UserSerializer queryset = User.objects - lookup_field = "nickname" - permission_classes = [permissions.IsAuthenticatedOrReadOnly] + lookup_field = None + permission_classes = [permissions.IsAuthenticated] def get_object(self, *args, **kwargs): request = self.request user = request.user - if request.method in WRITE_METHODS: - # May raise a permission denied - self.check_object_permissions(self.request, user) - return user - return super().get_object(*args, **kwargs) + # May raise a permission denied + self.check_object_permissions(self.request, user) - def list(self, request, *args, **kwargs): - self.permission_classes = [permissions.IsAuthenticated] - self.lookup_field = None - serializer = self.get_serializer( - get_object_or_404(User, email=request.user), many=False - ) - return Response(serializer.data) + return user + + +class UserProfileViewSet(mixins.RetrieveModelMixin, GenericViewSet): + """ + Get user profile + """ + + serializer_class = UserSerializer + queryset = User.objects + lookup_field = "nickname" class SearchUserViewSet(mixins.ListModelMixin, GenericViewSet): diff --git a/bothub/api/v2/routers.py b/bothub/api/v2/routers.py index b7881f5a..9f471822 100644 --- a/bothub/api/v2/routers.py +++ b/bothub/api/v2/routers.py @@ -24,6 +24,7 @@ from .account.views import ChangePasswordViewSet from .account.views import RequestResetPasswordViewSet from .account.views import UserProfileViewSet +from .account.views import MyUserProfileViewSet from .account.views import SearchUserViewSet from .account.views import ResetPasswordViewSet from .translation.views import RepositoryTranslatedExampleViewSet @@ -140,5 +141,6 @@ def get_lookup_regex(self, viewset, lookup_prefix=""): router.register("account/change-password", ChangePasswordViewSet) router.register("account/forgot-password", RequestResetPasswordViewSet) router.register("account/user-profile", UserProfileViewSet) +router.register("account/my-profile", MyUserProfileViewSet) router.register("account/search-user", SearchUserViewSet) router.register("account/reset-password", ResetPasswordViewSet) From 25bb3a320aa26a0b077861774c81bd295a872334 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Mon, 21 Oct 2019 09:11:04 -0300 Subject: [PATCH 186/207] [fix] Migrations --- .../0032_repository_total_updates.py | 31 +++++++++++++++++++ .../migrations/0037_auto_20191011_2021.py | 16 +--------- 2 files changed, 32 insertions(+), 15 deletions(-) create mode 100644 bothub/common/migrations/0032_repository_total_updates.py diff --git a/bothub/common/migrations/0032_repository_total_updates.py b/bothub/common/migrations/0032_repository_total_updates.py new file mode 100644 index 00000000..77b7f9ab --- /dev/null +++ b/bothub/common/migrations/0032_repository_total_updates.py @@ -0,0 +1,31 @@ +# Generated by Django 2.1.5 on 2019-08-14 19:45 + +from django.db import migrations, models + +from bothub.common.models import RepositoryUpdate +from bothub.common.models import Repository + + +def updateRepository(apps, schema_editor): + for update in RepositoryUpdate.objects.all().filter( + trained_at__isnull=False + ): + repository = Repository.objects.get(uuid=update.repository.uuid) + repository.total_updates += 1 + repository.save() + + +class Migration(migrations.Migration): + + dependencies = [ + ('common', '0031_auto_20190502_1732'), + ] + + operations = [ + migrations.AddField( + model_name='repository', + name='total_updates', + field=models.IntegerField(default=0, verbose_name='total updates'), + ), + migrations.RunPython(updateRepository), + ] diff --git a/bothub/common/migrations/0037_auto_20191011_2021.py b/bothub/common/migrations/0037_auto_20191011_2021.py index e43f6dbb..49bdd9ee 100644 --- a/bothub/common/migrations/0037_auto_20191011_2021.py +++ b/bothub/common/migrations/0037_auto_20191011_2021.py @@ -5,14 +5,6 @@ from django.conf import settings from bothub.utils import send_bot_data_file_aws from bothub.common.models import RepositoryUpdate -from bothub.common.models import Repository - - -def updateRepository(apps, schema_editor): - for update in RepositoryUpdate.objects.all().filter(trained_at__isnull=False): - repository = Repository.objects.get(uuid=update.repository.uuid) - repository.total_updates += 1 - repository.save() def update_repository(apps, schema_editor): @@ -27,7 +19,7 @@ def update_repository(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [("common", "0031_auto_20190502_1732")] + dependencies = [("common", "0032_repository_total_updates")] operations = [ migrations.RemoveField(model_name="repositoryvote", name="vote"), @@ -36,12 +28,6 @@ class Migration(migrations.Migration): name="nlp_server", field=models.URLField(blank=True, null=True, verbose_name="Base URL NLP"), ), - migrations.AddField( - model_name="repository", - name="total_updates", - field=models.IntegerField(default=0, verbose_name="total updates"), - ), - migrations.RunPython(updateRepository), migrations.AddField( model_name="repositoryvote", name="created", From 19c005e43b0cf063d7d3cf19a7f3e1da853b3e81 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Tue, 22 Oct 2019 10:10:08 -0300 Subject: [PATCH 187/207] [fix] Tests Profile --- bothub/api/v2/tests/test_account.py | 32 +++++++++++++++---- .../0032_repository_total_updates.py | 14 +++----- 2 files changed, 31 insertions(+), 15 deletions(-) diff --git a/bothub/api/v2/tests/test_account.py b/bothub/api/v2/tests/test_account.py index 582c35de..c6b118fa 100644 --- a/bothub/api/v2/tests/test_account.py +++ b/bothub/api/v2/tests/test_account.py @@ -13,6 +13,7 @@ from ..account.views import RequestResetPasswordViewSet from ..account.views import ResetPasswordViewSet from ..account.views import UserProfileViewSet +from ..account.views import MyUserProfileViewSet from .utils import create_user_and_token @@ -215,7 +216,7 @@ def setUp(self): self.factory = RequestFactory() self.user, self.user_token = create_user_and_token() - def request(self, token, nickname): + def request(self, nickname): request = self.factory.get("/v2/account/user-profile/{}/".format(nickname)) response = UserProfileViewSet.as_view({"get": "retrieve"})( request, nickname=nickname @@ -225,16 +226,35 @@ def request(self, token, nickname): return (response, content_data) def test_okay(self): - response, content_data = self.request(self.user_token, self.user.nickname) + response, content_data = self.request(self.user.nickname) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(content_data.get("nickname"), self.user.nickname) def test_not_exists(self): - response, content_data = self.request(self.user_token, "no_exists") + response, content_data = self.request("no_exists") self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) self.assertEqual(content_data.get("detail"), "Not found.") +class ListMyProfileTestCase(TestCase): + def setUp(self): + self.factory = RequestFactory() + self.user, self.user_token = create_user_and_token() + + def request(self, token): + authorization_header = {"HTTP_AUTHORIZATION": "Token {}".format(token.key)} + request = self.factory.get("/v2/account/my-profile/", **authorization_header) + response = MyUserProfileViewSet.as_view({"get": "retrieve"})(request) + response.render() + content_data = json.loads(response.content) + return (response, content_data) + + def test_okay(self): + response, content_data = self.request(self.user_token) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(content_data.get("nickname"), self.user.nickname) + + class UserUpdateTestCase(TestCase): def setUp(self): self.factory = RequestFactory() @@ -243,13 +263,13 @@ def setUp(self): def request(self, user, data, token): authorization_header = {"HTTP_AUTHORIZATION": "Token {}".format(token.key)} request = self.factory.patch( - "/v2/account/user-profile/{}/".format(self.user.nickname), + "/v2/account/my-profile/", self.factory._encode_data(data, MULTIPART_CONTENT), MULTIPART_CONTENT, **authorization_header ) - response = UserProfileViewSet.as_view({"patch": "update"})( - request, pk=user.pk, nickname=user.nickname, partial=True + response = MyUserProfileViewSet.as_view({"patch": "update"})( + request, pk=user.pk, partial=True ) response.render() content_data = json.loads(response.content) diff --git a/bothub/common/migrations/0032_repository_total_updates.py b/bothub/common/migrations/0032_repository_total_updates.py index 77b7f9ab..e57dd2de 100644 --- a/bothub/common/migrations/0032_repository_total_updates.py +++ b/bothub/common/migrations/0032_repository_total_updates.py @@ -7,9 +7,7 @@ def updateRepository(apps, schema_editor): - for update in RepositoryUpdate.objects.all().filter( - trained_at__isnull=False - ): + for update in RepositoryUpdate.objects.all().filter(trained_at__isnull=False): repository = Repository.objects.get(uuid=update.repository.uuid) repository.total_updates += 1 repository.save() @@ -17,15 +15,13 @@ def updateRepository(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ - ('common', '0031_auto_20190502_1732'), - ] + dependencies = [("common", "0031_auto_20190502_1732")] operations = [ migrations.AddField( - model_name='repository', - name='total_updates', - field=models.IntegerField(default=0, verbose_name='total updates'), + model_name="repository", + name="total_updates", + field=models.IntegerField(default=0, verbose_name="total updates"), ), migrations.RunPython(updateRepository), ] From 96f98f20d663c76da9997fb4f6d5120e986bea6f Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Tue, 22 Oct 2019 11:38:41 -0300 Subject: [PATCH 188/207] Added options key disabled_options --- bothub/api/v2/metadata.py | 4 ++++ bothub/api/v2/repository/serializers.py | 23 ++++++++++++++++++----- bothub/api/v2/repository/views.py | 1 + 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/bothub/api/v2/metadata.py b/bothub/api/v2/metadata.py index e436cd99..ccf17e25 100644 --- a/bothub/api/v2/metadata.py +++ b/bothub/api/v2/metadata.py @@ -106,6 +106,10 @@ def get_field_info(self, field): # pragma: no cover elif getattr(field, "fields", None): field_info["children"] = self.get_serializer_info(field) + if field_info.get("style").get("disabled_options"): + field_info["disabled_options"] = field_info["style"]["disabled_options"] + field_info["style"].pop("disabled_options") + if not field_info.get("read_only") and hasattr(field, "choices"): field_info["choices"] = [ { diff --git a/bothub/api/v2/repository/serializers.py b/bothub/api/v2/repository/serializers.py index a7cdfd97..0f66f922 100644 --- a/bothub/api/v2/repository/serializers.py +++ b/bothub/api/v2/repository/serializers.py @@ -42,11 +42,18 @@ class Meta: ] ref_name = None + id = serializers.IntegerField( + read_only=True, required=False, label="ID", style={"disabled_options": True} + ) + repository = serializers.PrimaryKeyRelatedField( - queryset=Repository.objects, style={"show": False}, required=False + queryset=Repository.objects, + style={"show": False, "disabled_options": True}, + required=False, ) user = serializers.HiddenField( - default=serializers.CurrentUserDefault(), style={"show": False} + default=serializers.CurrentUserDefault(), + style={"show": False, "disabled_options": True}, ) text = TextField( label=_("Leave a message for repository administrators"), @@ -55,13 +62,19 @@ class Meta: required=False, ) user__nickname = serializers.SlugRelatedField( - source="user", slug_field="nickname", read_only=True + source="user", + slug_field="nickname", + read_only=True, + style={"disabled_options": True}, ) approved_by__nickname = serializers.SlugRelatedField( - source="approved_by", slug_field="nickname", read_only=True + source="approved_by", + slug_field="nickname", + read_only=True, + style={"disabled_options": True}, ) approved_by = serializers.PrimaryKeyRelatedField( - read_only=True, style={"show": False} + read_only=True, style={"show": False, "disabled_options": True} ) def update(self, instance, validated_data): diff --git a/bothub/api/v2/repository/views.py b/bothub/api/v2/repository/views.py index ad016349..f3388a05 100644 --- a/bothub/api/v2/repository/views.py +++ b/bothub/api/v2/repository/views.py @@ -391,6 +391,7 @@ class RepositoryAuthorizationRequestsViewSet( serializer_class = RequestRepositoryAuthorizationSerializer filter_class = RepositoryAuthorizationRequestsFilter permission_classes = [IsAuthenticated] + metadata_class = Metadata def create(self, request, *args, **kwargs): self.queryset = RequestRepositoryAuthorization.objects From f5a9b9c2ace1c7a7db7cfd566637089ca63c3c0d Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Tue, 22 Oct 2019 11:45:26 -0300 Subject: [PATCH 189/207] Removed key disable_options, using key show in style --- bothub/api/v2/metadata.py | 4 ---- bothub/api/v2/repository/serializers.py | 13 +++++++------ 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/bothub/api/v2/metadata.py b/bothub/api/v2/metadata.py index ccf17e25..e436cd99 100644 --- a/bothub/api/v2/metadata.py +++ b/bothub/api/v2/metadata.py @@ -106,10 +106,6 @@ def get_field_info(self, field): # pragma: no cover elif getattr(field, "fields", None): field_info["children"] = self.get_serializer_info(field) - if field_info.get("style").get("disabled_options"): - field_info["disabled_options"] = field_info["style"]["disabled_options"] - field_info["style"].pop("disabled_options") - if not field_info.get("read_only") and hasattr(field, "choices"): field_info["choices"] = [ { diff --git a/bothub/api/v2/repository/serializers.py b/bothub/api/v2/repository/serializers.py index 0f66f922..526f78f8 100644 --- a/bothub/api/v2/repository/serializers.py +++ b/bothub/api/v2/repository/serializers.py @@ -43,17 +43,17 @@ class Meta: ref_name = None id = serializers.IntegerField( - read_only=True, required=False, label="ID", style={"disabled_options": True} + read_only=True, required=False, label="ID", style={"show": False} ) repository = serializers.PrimaryKeyRelatedField( queryset=Repository.objects, - style={"show": False, "disabled_options": True}, + style={"show": False}, required=False, ) user = serializers.HiddenField( default=serializers.CurrentUserDefault(), - style={"show": False, "disabled_options": True}, + style={"show": False}, ) text = TextField( label=_("Leave a message for repository administrators"), @@ -65,17 +65,18 @@ class Meta: source="user", slug_field="nickname", read_only=True, - style={"disabled_options": True}, + style={"show": False}, ) approved_by__nickname = serializers.SlugRelatedField( source="approved_by", slug_field="nickname", read_only=True, - style={"disabled_options": True}, + style={"show": False}, ) approved_by = serializers.PrimaryKeyRelatedField( - read_only=True, style={"show": False, "disabled_options": True} + read_only=True, style={"show": False} ) + created_at = serializers.DateTimeField(required=False, read_only=True, style={"show": False}) def update(self, instance, validated_data): validated_data.update({"approved_by": self.context["request"].user}) From a7f355264f1b83926df13acf4114d2e12ae70ff0 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Tue, 22 Oct 2019 13:12:44 -0300 Subject: [PATCH 190/207] [fix] Router Search Repositories, removed is_private --- bothub/api/v2/repository/views.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bothub/api/v2/repository/views.py b/bothub/api/v2/repository/views.py index f3388a05..b6ff4857 100644 --- a/bothub/api/v2/repository/views.py +++ b/bothub/api/v2/repository/views.py @@ -325,7 +325,8 @@ def get_queryset(self, *args, **kwargs): return self.queryset.filter( owner__nickname=self.request.query_params.get( "nickname", self.request.user - ) + ), + is_private=False ) else: return self.queryset.filter(owner=self.request.user) From c352adbde78dbaae3ba45ebd0085824f3dbcb456 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Tue, 22 Oct 2019 13:30:18 -0300 Subject: [PATCH 191/207] [fix] Labels Repository Examples --- bothub/api/v2/example/serializers.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/bothub/api/v2/example/serializers.py b/bothub/api/v2/example/serializers.py index 1c51c3c5..514fe0a0 100644 --- a/bothub/api/v2/example/serializers.py +++ b/bothub/api/v2/example/serializers.py @@ -73,3 +73,8 @@ class Meta: ref_name = None entities = RepositoryExampleEntitySerializer(many=True, read_only=True) + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + if kwargs.get('context').get('request').method == 'GET': + self.fields["entities"] = RepositoryExampleEntitySerializer(many=True, read_only=True, data='GET') From 893f60e9235c46a81280cd9ca207be665f7435bc Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Tue, 22 Oct 2019 16:21:32 -0300 Subject: [PATCH 192/207] [fix] Update Repository Authorization --- bothub/api/v2/repository/serializers.py | 1 + 1 file changed, 1 insertion(+) diff --git a/bothub/api/v2/repository/serializers.py b/bothub/api/v2/repository/serializers.py index 526f78f8..79b74ace 100644 --- a/bothub/api/v2/repository/serializers.py +++ b/bothub/api/v2/repository/serializers.py @@ -79,6 +79,7 @@ class Meta: created_at = serializers.DateTimeField(required=False, read_only=True, style={"show": False}) def update(self, instance, validated_data): + validated_data.pop('user') validated_data.update({"approved_by": self.context["request"].user}) return super().update(instance, validated_data) From 733ce09e605e3fa99fb3bfe9b9972fa4fd38636e Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Wed, 23 Oct 2019 10:23:06 -0300 Subject: [PATCH 193/207] Added update last_login User and PEP-8 --- bothub/api/v2/account/views.py | 5 +++++ bothub/api/v2/example/serializers.py | 6 ++++-- bothub/api/v2/repository/serializers.py | 18 +++++++----------- bothub/api/v2/repository/views.py | 2 +- 4 files changed, 17 insertions(+), 14 deletions(-) diff --git a/bothub/api/v2/account/views.py b/bothub/api/v2/account/views.py index a87ffbdc..7aed3380 100644 --- a/bothub/api/v2/account/views.py +++ b/bothub/api/v2/account/views.py @@ -1,3 +1,4 @@ +from django.utils import timezone from django.utils.decorators import method_decorator from django_filters.rest_framework import DjangoFilterBackend from drf_yasg.utils import swagger_auto_schema @@ -38,6 +39,10 @@ def create(self, request, *args, **kwargs): ) serializer.is_valid(raise_exception=True) user = serializer.validated_data["user"] + + user.last_login = timezone.now() + user.save(update_fields=["last_login"]) + token, created = Token.objects.get_or_create(user=user) return Response( {"token": token.key}, diff --git a/bothub/api/v2/example/serializers.py b/bothub/api/v2/example/serializers.py index 514fe0a0..1ab65658 100644 --- a/bothub/api/v2/example/serializers.py +++ b/bothub/api/v2/example/serializers.py @@ -76,5 +76,7 @@ class Meta: def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - if kwargs.get('context').get('request').method == 'GET': - self.fields["entities"] = RepositoryExampleEntitySerializer(many=True, read_only=True, data='GET') + if kwargs.get("context").get("request").method == "GET": + self.fields["entities"] = RepositoryExampleEntitySerializer( + many=True, read_only=True, data="GET" + ) diff --git a/bothub/api/v2/repository/serializers.py b/bothub/api/v2/repository/serializers.py index 79b74ace..f6649b6f 100644 --- a/bothub/api/v2/repository/serializers.py +++ b/bothub/api/v2/repository/serializers.py @@ -47,13 +47,10 @@ class Meta: ) repository = serializers.PrimaryKeyRelatedField( - queryset=Repository.objects, - style={"show": False}, - required=False, + queryset=Repository.objects, style={"show": False}, required=False ) user = serializers.HiddenField( - default=serializers.CurrentUserDefault(), - style={"show": False}, + default=serializers.CurrentUserDefault(), style={"show": False} ) text = TextField( label=_("Leave a message for repository administrators"), @@ -62,10 +59,7 @@ class Meta: required=False, ) user__nickname = serializers.SlugRelatedField( - source="user", - slug_field="nickname", - read_only=True, - style={"show": False}, + source="user", slug_field="nickname", read_only=True, style={"show": False} ) approved_by__nickname = serializers.SlugRelatedField( source="approved_by", @@ -76,10 +70,12 @@ class Meta: approved_by = serializers.PrimaryKeyRelatedField( read_only=True, style={"show": False} ) - created_at = serializers.DateTimeField(required=False, read_only=True, style={"show": False}) + created_at = serializers.DateTimeField( + required=False, read_only=True, style={"show": False} + ) def update(self, instance, validated_data): - validated_data.pop('user') + validated_data.pop("user") validated_data.update({"approved_by": self.context["request"].user}) return super().update(instance, validated_data) diff --git a/bothub/api/v2/repository/views.py b/bothub/api/v2/repository/views.py index b6ff4857..7a67f648 100644 --- a/bothub/api/v2/repository/views.py +++ b/bothub/api/v2/repository/views.py @@ -326,7 +326,7 @@ def get_queryset(self, *args, **kwargs): owner__nickname=self.request.query_params.get( "nickname", self.request.user ), - is_private=False + is_private=False, ) else: return self.queryset.filter(owner=self.request.user) From d9ce6c833fd4e3dc9d70f49cae1f2173c0ebdf5e Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Wed, 23 Oct 2019 10:35:08 -0300 Subject: [PATCH 194/207] [fix] PEP-8 and Conflicts --- bothub/authentication/models.py | 4 ++-- bothub/common/models.py | 5 ++++- bothub/settings.py | 3 ++- bothub/urls.py | 4 +++- 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/bothub/authentication/models.py b/bothub/authentication/models.py index 22a5bc62..f0b8c406 100644 --- a/bothub/authentication/models.py +++ b/bothub/authentication/models.py @@ -90,7 +90,7 @@ def token_generator(self): return PasswordResetTokenGenerator() def send_welcome_email(self): - if not settings.SEND_EMAILS + if not settings.SEND_EMAILS: return False # pragma: no cover context = {"name": self.name, "base_url": settings.BASE_URL} send_mail( @@ -113,7 +113,7 @@ def send_reset_password_email(self): reset_url = "{}reset-password/{}/{}/".format( settings.BOTHUB_WEBAPP_BASE_URL, self.nickname, token ) - context = {"reset_url": reset_url, 'base_url': settings.BASE_URL} + context = {"reset_url": reset_url, "base_url": settings.BASE_URL} send_mail( _("Reset your bothub password"), render_to_string("authentication/emails/reset_password.txt", context), diff --git a/bothub/common/models.py b/bothub/common/models.py index 8e945676..a4850e25 100644 --- a/bothub/common/models.py +++ b/bothub/common/models.py @@ -1126,7 +1126,10 @@ def send_new_request_email_to_admins(self): def send_request_rejected_email(self): if not settings.SEND_EMAILS: return False # pragma: no cover - context = {"repository_name": self.repository.name, "base_url": settings.BASE_URL} + context = { + "repository_name": self.repository.name, + "base_url": settings.BASE_URL, + } send_mail( _("Access denied to {}").format(self.repository.name), render_to_string("common/emails/request_rejected.txt", context), diff --git a/bothub/settings.py b/bothub/settings.py index 63fc2f73..11cad2e6 100644 --- a/bothub/settings.py +++ b/bothub/settings.py @@ -45,6 +45,7 @@ BOTHUB_ENGINE_AWS_S3_BUCKET_NAME=(str, ""), BOTHUB_ENGINE_AWS_REGION_NAME=(str, "us-east-1"), BOTHUB_ENGINE_AWS_SEND=(bool, False), + BASE_URL=(str, "http://api.bothub.it/"), ) # Build paths inside the project like this: os.path.join(BASE_DIR, ...) @@ -59,7 +60,7 @@ ALLOWED_HOSTS = env.list("ALLOWED_HOSTS") -BASE_URL = config('BASE_URL', default='') +BASE_URL = env.str("BASE_URL") # Application definition diff --git a/bothub/urls.py b/bothub/urls.py index 4518c976..9d9d2bd5 100644 --- a/bothub/urls.py +++ b/bothub/urls.py @@ -56,7 +56,9 @@ def wrapper(request): path( "welcome/", render_template( - "authentication/emails/welcome.html", name="User", base_url=settings.BASE_URL + "authentication/emails/welcome.html", + name="User", + base_url=settings.BASE_URL, ), ), path( From d1a647af7a78a81c72a72c375501bae9ac1ab1fe Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Wed, 23 Oct 2019 10:40:29 -0300 Subject: [PATCH 195/207] Added BASE_URL README --- README.md | 1 + docker-compose.yml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index b83f36df..93164d27 100644 --- a/README.md +++ b/README.md @@ -63,6 +63,7 @@ You can set environment variables in your OS, write on ```.env``` file or pass v |--|--|--|--| | SECRET_KEY | ```string```| ```None``` | A secret key for a particular Django installation. This is used to provide cryptographic signing, and should be set to a unique, unpredictable value. | DEBUG | ```boolean``` | ```False``` | A boolean that turns on/off debug mode. +| BASE_URL | ```string``` | ```http://api.bothub.it/``` | URL Base Bothub Engine Backend. | ALLOWED_HOSTS | ```string``` | ```*``` | A list of strings representing the host/domain names that this Django site can serve. | DEFAULT_DATABASE | ```string``` | ```sqlite:///db.sqlite3``` | Read [dj-database-url](https://github.com/kennethreitz/dj-database-url) to configure the database connection. | LANGUAGE_CODE | ```string``` | ```en-us``` | A string representing the language code for this installation.This should be in standard [language ID format](https://docs.djangoproject.com/en/2.0/topics/i18n/#term-language-code). diff --git a/docker-compose.yml b/docker-compose.yml index 38d37d37..5243ef05 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -50,7 +50,7 @@ services: - CHECK_ACCESSIBLE_API_URL=${CHECK_ACCESSIBLE_API_URL} - SEND_EMAILS=${SEND_EMAILS:-true} - SUPPORTED_LANGUAGES=${SUPPORTED_LANGUAGES:-en|pt} - - BASE_URL=${BOTHUB_BACKEND_BASE_URL:-https://api.bothub.ti/} + - BASE_URL=${BOTHUB_BACKEND_BASE_URL:-https://api.bothub.it/} - BOTHUB_ENGINE_AWS_ACCESS_KEY_ID=${BOTHUB_ENGINE_AWS_ACCESS_KEY_ID} - BOTHUB_ENGINE_AWS_SECRET_ACCESS_KEY=${BOTHUB_ENGINE_AWS_SECRET_ACCESS_KEY} - BOTHUB_ENGINE_AWS_S3_BUCKET_NAME=${BOTHUB_ENGINE_AWS_S3_BUCKET_NAME} From 685fd4ab4ab8fb44d61df34bd90cc8fa9496984b Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Wed, 23 Oct 2019 11:20:55 -0300 Subject: [PATCH 196/207] [fix] Authorization Request Delete --- README.md | 2 +- bothub/api/v2/repository/serializers.py | 5 +++-- bothub/common/models.py | 2 ++ bothub/settings.py | 2 +- docker-compose.yml | 2 +- 5 files changed, 8 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 93164d27..6691da8f 100644 --- a/README.md +++ b/README.md @@ -63,7 +63,7 @@ You can set environment variables in your OS, write on ```.env``` file or pass v |--|--|--|--| | SECRET_KEY | ```string```| ```None``` | A secret key for a particular Django installation. This is used to provide cryptographic signing, and should be set to a unique, unpredictable value. | DEBUG | ```boolean``` | ```False``` | A boolean that turns on/off debug mode. -| BASE_URL | ```string``` | ```http://api.bothub.it/``` | URL Base Bothub Engine Backend. +| BASE_URL | ```string``` | ```http://api.bothub.it``` | URL Base Bothub Engine Backend. | ALLOWED_HOSTS | ```string``` | ```*``` | A list of strings representing the host/domain names that this Django site can serve. | DEFAULT_DATABASE | ```string``` | ```sqlite:///db.sqlite3``` | Read [dj-database-url](https://github.com/kennethreitz/dj-database-url) to configure the database connection. | LANGUAGE_CODE | ```string``` | ```en-us``` | A string representing the language code for this installation.This should be in standard [language ID format](https://docs.djangoproject.com/en/2.0/topics/i18n/#term-language-code). diff --git a/bothub/api/v2/repository/serializers.py b/bothub/api/v2/repository/serializers.py index f6649b6f..f4affad5 100644 --- a/bothub/api/v2/repository/serializers.py +++ b/bothub/api/v2/repository/serializers.py @@ -68,14 +68,15 @@ class Meta: style={"show": False}, ) approved_by = serializers.PrimaryKeyRelatedField( - read_only=True, style={"show": False} + read_only=True, style={"show": False}, required=False ) created_at = serializers.DateTimeField( required=False, read_only=True, style={"show": False} ) def update(self, instance, validated_data): - validated_data.pop("user") + if 'user' in validated_data: + validated_data.pop("user") validated_data.update({"approved_by": self.context["request"].user}) return super().update(instance, validated_data) diff --git a/bothub/common/models.py b/bothub/common/models.py index a4850e25..e10877e7 100644 --- a/bothub/common/models.py +++ b/bothub/common/models.py @@ -1364,4 +1364,6 @@ def send_new_request_email_to_admins_on_created(instance, created, **kwargs): @receiver(models.signals.post_delete, sender=RequestRepositoryAuthorization) def send_request_rejected_email(instance, **kwargs): + user_authorization = instance.repository.get_user_authorization(instance.user) + user_authorization.delete() instance.send_request_rejected_email() diff --git a/bothub/settings.py b/bothub/settings.py index 11cad2e6..f43993ba 100644 --- a/bothub/settings.py +++ b/bothub/settings.py @@ -45,7 +45,7 @@ BOTHUB_ENGINE_AWS_S3_BUCKET_NAME=(str, ""), BOTHUB_ENGINE_AWS_REGION_NAME=(str, "us-east-1"), BOTHUB_ENGINE_AWS_SEND=(bool, False), - BASE_URL=(str, "http://api.bothub.it/"), + BASE_URL=(str, "http://api.bothub.it"), ) # Build paths inside the project like this: os.path.join(BASE_DIR, ...) diff --git a/docker-compose.yml b/docker-compose.yml index 5243ef05..f5082a84 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -50,7 +50,7 @@ services: - CHECK_ACCESSIBLE_API_URL=${CHECK_ACCESSIBLE_API_URL} - SEND_EMAILS=${SEND_EMAILS:-true} - SUPPORTED_LANGUAGES=${SUPPORTED_LANGUAGES:-en|pt} - - BASE_URL=${BOTHUB_BACKEND_BASE_URL:-https://api.bothub.it/} + - BASE_URL=${BOTHUB_BACKEND_BASE_URL:-https://api.bothub.it} - BOTHUB_ENGINE_AWS_ACCESS_KEY_ID=${BOTHUB_ENGINE_AWS_ACCESS_KEY_ID} - BOTHUB_ENGINE_AWS_SECRET_ACCESS_KEY=${BOTHUB_ENGINE_AWS_SECRET_ACCESS_KEY} - BOTHUB_ENGINE_AWS_S3_BUCKET_NAME=${BOTHUB_ENGINE_AWS_S3_BUCKET_NAME} From 0cce356b284d85e5123f30a1a9f4ca793e7c414c Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Wed, 23 Oct 2019 11:34:13 -0300 Subject: [PATCH 197/207] [fix] Validation Check Role is not LEVEL_NOTHING 0 --- bothub/api/v2/repository/serializers.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bothub/api/v2/repository/serializers.py b/bothub/api/v2/repository/serializers.py index f4affad5..7f4a4237 100644 --- a/bothub/api/v2/repository/serializers.py +++ b/bothub/api/v2/repository/serializers.py @@ -382,6 +382,8 @@ class Meta: def validate(self, data): if self.instance.user == self.instance.repository.owner: raise PermissionDenied(_("The owner role can't be changed.")) + if data.get('role') == RepositoryAuthorization.LEVEL_NOTHING: + raise PermissionDenied(_("You cannot set user role 0")) return data From 541d87585513d415e505c40ca1ff0c7f9691a2b7 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Wed, 23 Oct 2019 13:17:33 -0300 Subject: [PATCH 198/207] Added Validation Update Role Authorization --- bothub/api/v2/repository/serializers.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bothub/api/v2/repository/serializers.py b/bothub/api/v2/repository/serializers.py index 7f4a4237..6025fd8f 100644 --- a/bothub/api/v2/repository/serializers.py +++ b/bothub/api/v2/repository/serializers.py @@ -75,7 +75,7 @@ class Meta: ) def update(self, instance, validated_data): - if 'user' in validated_data: + if "user" in validated_data: validated_data.pop("user") validated_data.update({"approved_by": self.context["request"].user}) return super().update(instance, validated_data) @@ -382,7 +382,7 @@ class Meta: def validate(self, data): if self.instance.user == self.instance.repository.owner: raise PermissionDenied(_("The owner role can't be changed.")) - if data.get('role') == RepositoryAuthorization.LEVEL_NOTHING: + if data.get("role") == RepositoryAuthorization.LEVEL_NOTHING: raise PermissionDenied(_("You cannot set user role 0")) return data From 52f178af22643911346bb83598d1725468ac367f Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Wed, 23 Oct 2019 13:24:58 -0300 Subject: [PATCH 199/207] Removed Routers NLP List Swagger Doc while not is DEBUG MODE --- bothub/api/v2/swagger.py | 26 ++++++++++++++++++++++++++ bothub/settings.py | 13 +++++++++++++ bothub/urls.py | 4 +++- 3 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 bothub/api/v2/swagger.py diff --git a/bothub/api/v2/swagger.py b/bothub/api/v2/swagger.py new file mode 100644 index 00000000..f25eef76 --- /dev/null +++ b/bothub/api/v2/swagger.py @@ -0,0 +1,26 @@ +from django.conf import settings +from drf_yasg.generators import OpenAPISchemaGenerator, EndpointEnumerator + + +class CustomEndpointEnumerator(EndpointEnumerator): + """ + Add custom setting to exclude views + """ + + def should_include_endpoint( + self, path, callback, app_name="", namespace="", url_name=None + ): + view = "{}.{}".format(callback.__module__, callback.__qualname__) + if view in settings.DRF_YASG_EXCLUDE_VIEWS: + return False + return super().should_include_endpoint( + path, callback, app_name, namespace, url_name + ) + + +class CustomOpenAPISchemaGenerator(OpenAPISchemaGenerator): + """ + We want change default endpoint enumerator class + """ + + endpoint_enumerator_class = CustomEndpointEnumerator diff --git a/bothub/settings.py b/bothub/settings.py index f43993ba..e0e65efe 100644 --- a/bothub/settings.py +++ b/bothub/settings.py @@ -258,6 +258,19 @@ }, } +DRF_YASG_EXCLUDE_VIEWS = ( + [ + "bothub.api.v2.nlp.views.RepositoryAuthorizationTrainViewSet", + "bothub.api.v2.nlp.views.RepositoryAuthorizationParseViewSet", + "bothub.api.v2.nlp.views.RepositoryAuthorizationInfoViewSet", + "bothub.api.v2.nlp.views.RepositoryAuthorizationEvaluateViewSet", + "bothub.api.v2.nlp.views.NLPLangsViewSet", + "bothub.api.v2.nlp.views.RepositoryUpdateInterpretersViewSet", + ] + if not DEBUG + else [] +) + # AWS AWS_SEND = env.bool("BOTHUB_ENGINE_AWS_SEND") diff --git a/bothub/urls.py b/bothub/urls.py index 9d9d2bd5..70dc4392 100644 --- a/bothub/urls.py +++ b/bothub/urls.py @@ -8,6 +8,7 @@ from bothub.api.v1.routers import router as bothub_api_routers from bothub.api.v2 import urls as bothub_api_v2_urls +from bothub.api.v2.swagger import CustomOpenAPISchemaGenerator from bothub.health.views import ping from bothub.health.views import r200 from bothub.common.views import download_bot_data @@ -23,7 +24,8 @@ license=openapi.License(name="GPL-3.0"), ), public=True, - permission_classes=[permissions.AllowAny], + permission_classes=(permissions.AllowAny,), + generator_class=CustomOpenAPISchemaGenerator, ) urlpatterns = [ From b8e2a6e9d3702ca85347edfc42e836c2d783c802 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Thu, 24 Oct 2019 17:49:15 -0300 Subject: [PATCH 200/207] [fix] Evaluate and Authorizations --- bothub/api/v2/evaluate/permissions.py | 4 +++- bothub/api/v2/repository/serializers.py | 9 +++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/bothub/api/v2/evaluate/permissions.py b/bothub/api/v2/evaluate/permissions.py index b06f4a35..fb1a29be 100644 --- a/bothub/api/v2/evaluate/permissions.py +++ b/bothub/api/v2/evaluate/permissions.py @@ -8,7 +8,9 @@ class RepositoryEvaluatePermission(permissions.BasePermission): def has_permission(self, request, view): try: - repository = Repository.objects.get(uuid=request.GET.get("repository_uuid")) + repository_uuid = request.data.get("repository") \ + if request.method in WRITE_METHODS else request.GET.get("repository_uuid") + repository = Repository.objects.get(uuid=repository_uuid) authorization = repository.get_user_authorization(request.user) if request.method in READ_METHODS and not request.user.is_authenticated: diff --git a/bothub/api/v2/repository/serializers.py b/bothub/api/v2/repository/serializers.py index 6025fd8f..b3e7b4a4 100644 --- a/bothub/api/v2/repository/serializers.py +++ b/bothub/api/v2/repository/serializers.py @@ -135,6 +135,7 @@ class Meta: "can_write", "is_admin", "created_at", + "id_request_authorizations" ] read_only = ["user", "user__nickname", "repository", "role", "created_at"] ref_name = None @@ -143,6 +144,14 @@ class Meta: source="user", slug_field="nickname", read_only=True ) + id_request_authorizations = serializers.SerializerMethodField() + + def get_id_request_authorizations(self, obj): + id_auth = RequestRepositoryAuthorization.objects.filter(repository=obj.repository, user=obj.user) + if id_auth.count() == 1: + return id_auth.first().pk + return None + class RepositorySerializer(serializers.ModelSerializer): class Meta: From a83f8ae8c51d5c6e00b5f2cf158f8807bfa8cc36 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Fri, 25 Oct 2019 15:41:47 -0300 Subject: [PATCH 201/207] [fix] Evaluate --- bothub/api/v2/evaluate/permissions.py | 7 +++++-- bothub/api/v2/nlp/views.py | 3 +-- bothub/api/v2/repository/serializers.py | 6 ++++-- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/bothub/api/v2/evaluate/permissions.py b/bothub/api/v2/evaluate/permissions.py index fb1a29be..a959ee24 100644 --- a/bothub/api/v2/evaluate/permissions.py +++ b/bothub/api/v2/evaluate/permissions.py @@ -8,8 +8,11 @@ class RepositoryEvaluatePermission(permissions.BasePermission): def has_permission(self, request, view): try: - repository_uuid = request.data.get("repository") \ - if request.method in WRITE_METHODS else request.GET.get("repository_uuid") + repository_uuid = ( + request.data.get("repository") + if request.method in WRITE_METHODS + else request.GET.get("repository_uuid") + ) repository = Repository.objects.get(uuid=repository_uuid) authorization = repository.get_user_authorization(request.user) diff --git a/bothub/api/v2/nlp/views.py b/bothub/api/v2/nlp/views.py index 13db2e84..f89ab0e8 100644 --- a/bothub/api/v2/nlp/views.py +++ b/bothub/api/v2/nlp/views.py @@ -1,5 +1,4 @@ import base64 -import json import requests from django.conf import settings @@ -337,7 +336,7 @@ def evaluate_results(self, request, **kwargs): intent_results=intents_score, matrix_chart=request.data.get("matrix_chart"), confidence_chart=request.data.get("confidence_chart"), - log=json.dumps(request.data.get("log")), + log=request.data.get("log"), ) return Response( diff --git a/bothub/api/v2/repository/serializers.py b/bothub/api/v2/repository/serializers.py index b3e7b4a4..0404d21a 100644 --- a/bothub/api/v2/repository/serializers.py +++ b/bothub/api/v2/repository/serializers.py @@ -135,7 +135,7 @@ class Meta: "can_write", "is_admin", "created_at", - "id_request_authorizations" + "id_request_authorizations", ] read_only = ["user", "user__nickname", "repository", "role", "created_at"] ref_name = None @@ -147,7 +147,9 @@ class Meta: id_request_authorizations = serializers.SerializerMethodField() def get_id_request_authorizations(self, obj): - id_auth = RequestRepositoryAuthorization.objects.filter(repository=obj.repository, user=obj.user) + id_auth = RequestRepositoryAuthorization.objects.filter( + repository=obj.repository, user=obj.user + ) if id_auth.count() == 1: return id_auth.first().pk return None From b5eb0e4cf552279ec65b156948acc705aaf37686 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Fri, 1 Nov 2019 17:08:47 -0300 Subject: [PATCH 202/207] Added Analyze Char and Updated Migrations --- README.md | 10 +++++++++ bothub/api/v2/nlp/views.py | 1 + bothub/api/v2/repository/serializers.py | 1 + bothub/common/admin.py | 1 + .../management/commands/transfer_train_aws.py | 18 ++++++++++++++++ .../commands/update_repository_tests.py | 15 +++++++++++++ .../0032_repository_total_updates.py | 10 +-------- .../migrations/0037_auto_20191011_2021.py | 14 ------------- .../migrations/0038_auto_20191101_1935.py | 21 +++++++++++++++++++ bothub/common/models.py | 6 ++++++ 10 files changed, 74 insertions(+), 23 deletions(-) create mode 100644 bothub/common/management/commands/transfer_train_aws.py create mode 100644 bothub/common/management/commands/update_repository_tests.py create mode 100644 bothub/common/migrations/0038_auto_20191101_1935.py diff --git a/README.md b/README.md index 6691da8f..e234fc5e 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,16 @@ Use ```make``` commands to ```check_environment```, ```install_requirements```, Run ```pipenv run python ./manage.py fill_db_using_fake_data``` to fill database using fake data. This can help you to test [Bothub Webapp](https://github.com/Ilhasoft/bothub-webapp). +### Update Repositories Tests + +Run ```pipenv run python ./manage.py update_repository_tests``` update repositories to sort by total tests. + + +### Migrate all training for aws + +Run ```pipenv run python ./manage.py transfer_train_aws``` Migrate all trainings to an aws bucket defined in project settings. + + #### Fake users infos: | nickname | email | password | is superuser | diff --git a/bothub/api/v2/nlp/views.py b/bothub/api/v2/nlp/views.py index f89ab0e8..ec895dc1 100644 --- a/bothub/api/v2/nlp/views.py +++ b/bothub/api/v2/nlp/views.py @@ -100,6 +100,7 @@ def start_training(self, request, **kwargs): "algorithm": repository.algorithm, "use_name_entities": repository.use_name_entities, "use_competing_intents": repository.use_competing_intents, + "use_analyze_char": repository.use_analyze_char, "ALGORITHM_STATISTICAL_MODEL": Repository.ALGORITHM_STATISTICAL_MODEL, "ALGORITHM_NEURAL_NETWORK_EXTERNAL": Repository.ALGORITHM_NEURAL_NETWORK_EXTERNAL, } diff --git a/bothub/api/v2/repository/serializers.py b/bothub/api/v2/repository/serializers.py index 0404d21a..65121fd4 100644 --- a/bothub/api/v2/repository/serializers.py +++ b/bothub/api/v2/repository/serializers.py @@ -193,6 +193,7 @@ class Meta: "use_language_model_featurizer", "use_competing_intents", "use_name_entities", + "use_analyze_char", "nlp_server", ] read_only = [ diff --git a/bothub/common/admin.py b/bothub/common/admin.py index 69b71d0c..0e828bac 100644 --- a/bothub/common/admin.py +++ b/bothub/common/admin.py @@ -17,6 +17,7 @@ class RepositoryUpdateInline(admin.TabularInline): "algorithm", "use_competing_intents", "use_name_entities", + "use_analyze_char", "created_at", "by", "training_started_at", diff --git a/bothub/common/management/commands/transfer_train_aws.py b/bothub/common/management/commands/transfer_train_aws.py new file mode 100644 index 00000000..df7fb6bd --- /dev/null +++ b/bothub/common/management/commands/transfer_train_aws.py @@ -0,0 +1,18 @@ +from django.conf import settings +from django.core.management.base import BaseCommand + +from bothub.common.models import RepositoryUpdate +from bothub.utils import send_bot_data_file_aws + + +class Command(BaseCommand): + def handle(self, *args, **kwargs): + if settings.AWS_SEND: + for update in RepositoryUpdate.objects.all().exclude(bot_data__exact=""): + repository_update = RepositoryUpdate.objects.get(pk=update.pk) + bot_data = send_bot_data_file_aws(update.pk, update.bot_data) + repository_update.bot_data = bot_data + repository_update.save(update_fields=["bot_data"]) + print("Updating bot_data repository_update {}".format(str(update.pk))) + else: + print("You need to configure the environment variables for AWS.") diff --git a/bothub/common/management/commands/update_repository_tests.py b/bothub/common/management/commands/update_repository_tests.py new file mode 100644 index 00000000..46623098 --- /dev/null +++ b/bothub/common/management/commands/update_repository_tests.py @@ -0,0 +1,15 @@ +from django.core.management.base import BaseCommand + +from bothub.common.models import Repository +from bothub.common.models import RepositoryUpdate + + +class Command(BaseCommand): + def handle(self, *args, **kwargs): + print("Updating...") + Repository.objects.all().update(total_updates=0) + for update in RepositoryUpdate.objects.all().filter(trained_at__isnull=False): + repository = Repository.objects.get(uuid=update.repository.uuid) + repository.total_updates += 1 + repository.save() + print("Repository UUID {} Updated".format(repository.pk)) diff --git a/bothub/common/migrations/0032_repository_total_updates.py b/bothub/common/migrations/0032_repository_total_updates.py index e57dd2de..a34835e5 100644 --- a/bothub/common/migrations/0032_repository_total_updates.py +++ b/bothub/common/migrations/0032_repository_total_updates.py @@ -6,13 +6,6 @@ from bothub.common.models import Repository -def updateRepository(apps, schema_editor): - for update in RepositoryUpdate.objects.all().filter(trained_at__isnull=False): - repository = Repository.objects.get(uuid=update.repository.uuid) - repository.total_updates += 1 - repository.save() - - class Migration(migrations.Migration): dependencies = [("common", "0031_auto_20190502_1732")] @@ -22,6 +15,5 @@ class Migration(migrations.Migration): model_name="repository", name="total_updates", field=models.IntegerField(default=0, verbose_name="total updates"), - ), - migrations.RunPython(updateRepository), + ) ] diff --git a/bothub/common/migrations/0037_auto_20191011_2021.py b/bothub/common/migrations/0037_auto_20191011_2021.py index 49bdd9ee..8344318f 100644 --- a/bothub/common/migrations/0037_auto_20191011_2021.py +++ b/bothub/common/migrations/0037_auto_20191011_2021.py @@ -2,19 +2,6 @@ import django.utils.timezone from django.db import migrations, models -from django.conf import settings -from bothub.utils import send_bot_data_file_aws -from bothub.common.models import RepositoryUpdate - - -def update_repository(apps, schema_editor): - if settings.AWS_SEND: - for update in RepositoryUpdate.objects.all().exclude(bot_data__exact=""): - repository_update = RepositoryUpdate.objects.get(pk=update.pk) - bot_data = send_bot_data_file_aws(update.pk, update.bot_data) - repository_update.bot_data = bot_data - repository_update.save(update_fields=["bot_data"]) - print("Updating bot_data repository_update {}".format(str(update.pk))) class Migration(migrations.Migration): @@ -35,7 +22,6 @@ class Migration(migrations.Migration): default=django.utils.timezone.now, editable=False ), ), - migrations.RunPython(update_repository), migrations.AlterField( model_name="repositoryupdate", name="bot_data", diff --git a/bothub/common/migrations/0038_auto_20191101_1935.py b/bothub/common/migrations/0038_auto_20191101_1935.py new file mode 100644 index 00000000..848b3a34 --- /dev/null +++ b/bothub/common/migrations/0038_auto_20191101_1935.py @@ -0,0 +1,21 @@ +# Generated by Django 2.1.11 on 2019-11-01 19:35 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [("common", "0037_auto_20191011_2021")] + + operations = [ + migrations.AddField( + model_name="repository", + name="use_analyze_char", + field=models.BooleanField(default=False, verbose_name="Use analyze char"), + ), + migrations.AddField( + model_name="repositoryupdate", + name="use_analyze_char", + field=models.BooleanField(default=False), + ), + ] diff --git a/bothub/common/models.py b/bothub/common/models.py index e10877e7..07d40b84 100644 --- a/bothub/common/models.py +++ b/bothub/common/models.py @@ -148,6 +148,7 @@ class Meta: ), default=False, ) + use_analyze_char = models.BooleanField(_("Use analyze char"), default=False) categories = models.ManyToManyField( RepositoryCategory, help_text=CATEGORIES_HELP_TEXT ) @@ -461,6 +462,7 @@ class Meta: trained_at = models.DateTimeField(_("trained at"), blank=True, null=True) failed_at = models.DateTimeField(_("failed at"), blank=True, null=True) training_log = models.TextField(_("training log"), blank=True, editable=False) + use_analyze_char = models.BooleanField(default=False) @property def examples(self): @@ -559,6 +561,8 @@ def ready_for_train(self): is not self.repository.use_name_entities ): return True + if previous_update.use_analyze_char is not self.repository.use_analyze_char: + return True if previous_update.failed_at: return True @@ -614,6 +618,7 @@ def start_training(self, by): self.algorithm = self.repository.algorithm self.use_competing_intents = self.repository.use_competing_intents self.use_name_entities = self.repository.use_name_entities + self.use_analyze_char = self.repository.use_analyze_char self.save( update_fields=[ "by", @@ -621,6 +626,7 @@ def start_training(self, by): "algorithm", "use_competing_intents", "use_name_entities", + "use_analyze_char", ] ) From 685b3da02287029aa8b981a7ea65d9bb2e8f524f Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Mon, 4 Nov 2019 11:31:09 -0300 Subject: [PATCH 203/207] Added route delete user if there is a repository whose user owns, the system replaces for the user of the system --- README.md | 3 +++ bothub/api/v2/account/views.py | 18 +++++++++++++++++- bothub/api/v2/tests/test_account.py | 28 ++++++++++++++++++++++++++++ bothub/authentication/models.py | 12 ++++++++++++ bothub/settings.py | 10 ++++++++++ 5 files changed, 70 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e234fc5e..70963fc3 100644 --- a/README.md +++ b/README.md @@ -100,3 +100,6 @@ You can set environment variables in your OS, write on ```.env``` file or pass v | BOTHUB_ENGINE_AWS_SECRET_ACCESS_KEY | ```string``` | ```None``` | | BOTHUB_ENGINE_AWS_REGION_NAME | ```string``` | ```None``` | | BOTHUB_ENGINE_AWS_SEND | ```bool``` | ```False``` | +| BOTHUB_BOT_EMAIL | ```string``` | ```bot_repository@bothub.it``` | Email that the system will automatically create for existing repositories that the owner deleted the account +| BOTHUB_BOT_NAME | ```string``` | ```Bot Repository``` | Name that the system will use to create the account +| BOTHUB_BOT_NICKNAME | ```string``` | ```bot_repository``` | Nickname that the system will use to create the account diff --git a/bothub/api/v2/account/views.py b/bothub/api/v2/account/views.py index 7aed3380..60ec1050 100644 --- a/bothub/api/v2/account/views.py +++ b/bothub/api/v2/account/views.py @@ -11,6 +11,8 @@ from bothub.api.v2.metadata import Metadata from bothub.authentication.models import User +from bothub.common.models import Repository +from bothub.common.models import RepositoryUpdate from .serializers import ChangePasswordSerializer from .serializers import LoginSerializer from .serializers import RegisterUserSerializer @@ -117,7 +119,10 @@ def create(self, request, *args, **kwargs): class MyUserProfileViewSet( - mixins.RetrieveModelMixin, mixins.UpdateModelMixin, GenericViewSet + mixins.RetrieveModelMixin, + mixins.UpdateModelMixin, + mixins.DestroyModelMixin, + GenericViewSet, ): """ Manager current user profile. @@ -143,6 +148,17 @@ def get_object(self, *args, **kwargs): return user + def destroy(self, request, *args, **kwargs): + repositories = Repository.objects.filter(owner=self.request.user) + repository_update = RepositoryUpdate.objects.filter(by=self.request.user) + user = User.generate_repository_user_bot() + + if repositories.count() > 0: + repositories.update(owner_id=user.pk) + if repository_update.count() > 0: + repository_update.update(by=user.pk) + return super().destroy(request, *args, **kwargs) + class UserProfileViewSet(mixins.RetrieveModelMixin, GenericViewSet): """ diff --git a/bothub/api/v2/tests/test_account.py b/bothub/api/v2/tests/test_account.py index c6b118fa..d035deee 100644 --- a/bothub/api/v2/tests/test_account.py +++ b/bothub/api/v2/tests/test_account.py @@ -6,6 +6,9 @@ from rest_framework import status from bothub.authentication.models import User +from bothub.common import languages +from bothub.common.models import Repository +from bothub.common.models import RepositoryExample from ..account.views import RegisterUserViewSet from ..account.views import LoginViewSet @@ -255,6 +258,31 @@ def test_okay(self): self.assertEqual(content_data.get("nickname"), self.user.nickname) +class DestroyMyProfileTestCase(TestCase): + def setUp(self): + self.factory = RequestFactory() + self.user, self.user_token = create_user_and_token() + + self.repository = Repository.objects.create( + owner=self.user, name="Testing", slug="test", language=languages.LANGUAGE_EN + ) + + def request(self, token): + authorization_header = {"HTTP_AUTHORIZATION": "Token {}".format(token.key)} + request = self.factory.delete("/v2/account/my-profile/", **authorization_header) + response = MyUserProfileViewSet.as_view({"delete": "destroy"})(request) + response.render() + return response + + def test_okay(self): + response = self.request(self.user_token) + self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) + + repository = Repository.objects.get(pk=self.repository.pk) + + self.assertEqual(repository.owner, User.generate_repository_user_bot()) + + class UserUpdateTestCase(TestCase): def setUp(self): self.factory = RequestFactory() diff --git a/bothub/authentication/models.py b/bothub/authentication/models.py index f0b8c406..41a5506b 100644 --- a/bothub/authentication/models.py +++ b/bothub/authentication/models.py @@ -127,6 +127,18 @@ def send_reset_password_email(self): def check_password_reset_token(self, token): return self.token_generator.check_token(self, token) + @staticmethod + def generate_repository_user_bot(): + user, create = User.objects.get_or_create( + email=settings.BOTHUB_BOT_EMAIL, + name=settings.BOTHUB_BOT_NAME, + nickname=settings.BOTHUB_BOT_NICKNAME, + locale="", + is_staff=False, + is_active=False, + ) + return user + @receiver(models.signals.post_save, sender=User) def send_welcome_email(instance, created, **kwargs): diff --git a/bothub/settings.py b/bothub/settings.py index e0e65efe..88cb81d9 100644 --- a/bothub/settings.py +++ b/bothub/settings.py @@ -46,6 +46,9 @@ BOTHUB_ENGINE_AWS_REGION_NAME=(str, "us-east-1"), BOTHUB_ENGINE_AWS_SEND=(bool, False), BASE_URL=(str, "http://api.bothub.it"), + BOTHUB_BOT_EMAIL=(str, "bot_repository@bothub.it"), + BOTHUB_BOT_NAME=(str, "Bot Repository"), + BOTHUB_BOT_NICKNAME=(str, "bot_repository"), ) # Build paths inside the project like this: os.path.join(BASE_DIR, ...) @@ -278,3 +281,10 @@ AWS_SECRET_ACCESS_KEY = env.str("BOTHUB_ENGINE_AWS_SECRET_ACCESS_KEY") AWS_BUCKET_NAME = env.str("BOTHUB_ENGINE_AWS_S3_BUCKET_NAME") AWS_REGION_NAME = env.str("BOTHUB_ENGINE_AWS_REGION_NAME") + + +# Account System for bots deleted + +BOTHUB_BOT_EMAIL = env.str("BOTHUB_BOT_EMAIL") +BOTHUB_BOT_NAME = env.str("BOTHUB_BOT_NAME") +BOTHUB_BOT_NICKNAME = env.str("BOTHUB_BOT_NICKNAME") From 0aba4086c938df4f4bdb8b89e3d507d964447657 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Mon, 4 Nov 2019 11:34:29 -0300 Subject: [PATCH 204/207] [fix] PEP8 --- bothub/api/v2/tests/test_account.py | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/bothub/api/v2/tests/test_account.py b/bothub/api/v2/tests/test_account.py index d035deee..cceec096 100644 --- a/bothub/api/v2/tests/test_account.py +++ b/bothub/api/v2/tests/test_account.py @@ -1,24 +1,21 @@ import json -from django.test import TestCase from django.test import RequestFactory +from django.test import TestCase from django.test.client import MULTIPART_CONTENT from rest_framework import status from bothub.authentication.models import User from bothub.common import languages from bothub.common.models import Repository -from bothub.common.models import RepositoryExample - -from ..account.views import RegisterUserViewSet -from ..account.views import LoginViewSet +from .utils import create_user_and_token from ..account.views import ChangePasswordViewSet +from ..account.views import LoginViewSet +from ..account.views import MyUserProfileViewSet +from ..account.views import RegisterUserViewSet from ..account.views import RequestResetPasswordViewSet from ..account.views import ResetPasswordViewSet from ..account.views import UserProfileViewSet -from ..account.views import MyUserProfileViewSet - -from .utils import create_user_and_token class LoginTestCase(TestCase): From c54298c62fd427b7bbafc8fee75cbd802ca7f78d Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Thu, 7 Nov 2019 17:28:16 -0300 Subject: [PATCH 205/207] Updated Router with Pagination NLP --- bothub/api/v2/nlp/views.py | 57 +++++++++++++++++++++++++++----------- 1 file changed, 41 insertions(+), 16 deletions(-) diff --git a/bothub/api/v2/nlp/views.py b/bothub/api/v2/nlp/views.py index ec895dc1..c8963d5f 100644 --- a/bothub/api/v2/nlp/views.py +++ b/bothub/api/v2/nlp/views.py @@ -8,7 +8,7 @@ from django.core.validators import URLValidator from django.core.exceptions import ValidationError -from rest_framework import mixins +from rest_framework import mixins, pagination from rest_framework import exceptions from rest_framework.decorators import action from rest_framework.response import Response @@ -40,12 +40,17 @@ def check_auth(request): raise exceptions.AuthenticationFailed(msg) +class NLPPagination(pagination.PageNumberPagination): + page_size = 2 + + class RepositoryAuthorizationTrainViewSet( mixins.RetrieveModelMixin, mixins.CreateModelMixin, GenericViewSet ): queryset = RepositoryAuthorization.objects serializer_class = NLPSerializer permission_classes = [AllowAny] + pagination_class = NLPPagination def retrieve(self, request, *args, **kwargs): check_auth(request) @@ -63,39 +68,59 @@ def retrieve(self, request, *args, **kwargs): } ) - @action(detail=True, methods=["POST"], url_name="start_training", lookup_field=[]) - def start_training(self, request, **kwargs): + @action(detail=True, methods=["GET"], url_name="get_examples", lookup_field=[]) + def get_examples(self, request, **kwargs): check_auth(request) - - repository = get_object_or_404( - RepositoryUpdate, pk=request.data.get("update_id") + queryset = get_object_or_404( + RepositoryUpdate, pk=request.query_params.get("update_id") ) + page = self.paginate_queryset(queryset.examples) + examples = [ {"example_id": example.id, "example_intent": example.intent} - for example in repository.examples + for example in page ] + return self.get_paginated_response(examples) - repository.start_training( - get_object_or_404(User, pk=request.data.get("by_user")) + @action( + detail=True, methods=["GET"], url_name="get_examples_labels", lookup_field=[] + ) + def get_examples_labels(self, request, **kwargs): + check_auth(request) + queryset = get_object_or_404( + RepositoryUpdate, pk=request.query_params.get("update_id") ) - label_examples_query = [] - - for label_examples in ( - repository.examples.filter(entities__entity__label__isnull=False) + page = self.paginate_queryset( + queryset.examples.filter(entities__entity__label__isnull=False) .annotate(entities_count=models.Count("entities")) .filter(entities_count__gt=0) - ): + ) + + label_examples_query = [] + + for label_examples in page: label_examples_query.append({"example_id": label_examples.id}) + return self.get_paginated_response(label_examples_query) + + @action(detail=True, methods=["POST"], url_name="start_training", lookup_field=[]) + def start_training(self, request, **kwargs): + check_auth(request) + + repository = get_object_or_404( + RepositoryUpdate, pk=request.data.get("update_id") + ) + + repository.start_training( + get_object_or_404(User, pk=request.data.get("by_user")) + ) return Response( { "language": repository.language, "update_id": repository.id, "repository_uuid": str(repository.repository.uuid), - "examples": examples, - "label_examples_query": label_examples_query, "intent": repository.intents, "algorithm": repository.algorithm, "use_name_entities": repository.use_name_entities, From 7ba30483245a9619bf12eeb48ba0de2057cf74c5 Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Thu, 7 Nov 2019 18:09:27 -0300 Subject: [PATCH 206/207] Updated Serializer --- bothub/api/v2/repository/serializers.py | 51 ++++++++++++++++--------- 1 file changed, 34 insertions(+), 17 deletions(-) diff --git a/bothub/api/v2/repository/serializers.py b/bothub/api/v2/repository/serializers.py index 65121fd4..8824b1c9 100644 --- a/bothub/api/v2/repository/serializers.py +++ b/bothub/api/v2/repository/serializers.py @@ -210,31 +210,48 @@ class Meta: ] ref_name = None + uuid = serializers.UUIDField(style={"show": False}, read_only=True) + available_languages = serializers.ReadOnlyField(style={"show": False}) + entities_list = serializers.ReadOnlyField(style={"show": False}) + labels_list = serializers.ReadOnlyField(style={"show": False}) + ready_for_train = serializers.ReadOnlyField(style={"show": False}) + created_at = serializers.DateTimeField(style={"show": False}, read_only=True) + requirements_to_train = serializers.ReadOnlyField(style={"show": False}) + languages_ready_for_train = serializers.ReadOnlyField(style={"show": False}) + languages_warnings = serializers.ReadOnlyField(style={"show": False}) + use_language_model_featurizer = serializers.ReadOnlyField(style={"show": False}) + language = serializers.ChoiceField( - LANGUAGE_CHOICES, label=Repository._meta.get_field("language").verbose_name + LANGUAGE_CHOICES, label=_("Language") ) - owner = serializers.PrimaryKeyRelatedField(read_only=True) + owner = serializers.PrimaryKeyRelatedField(read_only=True, style={"show": False}) owner__nickname = serializers.SlugRelatedField( - source="owner", slug_field="nickname", read_only=True + source="owner", slug_field="nickname", read_only=True, style={"show": False} ) - intents = serializers.SerializerMethodField() - intents_list = serializers.SerializerMethodField() - categories = RepositoryCategorySerializer(many=True, read_only=True) + intents = serializers.SerializerMethodField(style={"show": False}) + intents_list = serializers.SerializerMethodField(style={"show": False}) categories_list = serializers.SlugRelatedField( - source="categories", slug_field="name", many=True, read_only=True + source="categories", slug_field="name", many=True, read_only=True, style={"show": False} + ) + categories = serializers.ManyRelatedField( + child_relation=serializers.PrimaryKeyRelatedField( + queryset=RepositoryCategory.objects.all() + ), + allow_empty=False, + help_text=Repository.CATEGORIES_HELP_TEXT, ) labels = RepositoryEntityLabelSerializer( - source="current_labels", many=True, read_only=True + source="current_labels", many=True, read_only=True, style={"show": False} ) - other_label = serializers.SerializerMethodField() - examples__count = serializers.SerializerMethodField() - evaluate_languages_count = serializers.SerializerMethodField() - absolute_url = serializers.SerializerMethodField() - authorization = serializers.SerializerMethodField() - request_authorization = serializers.SerializerMethodField() - available_request_authorization = serializers.SerializerMethodField() - entities = serializers.SerializerMethodField() - nlp_server = serializers.SerializerMethodField() + other_label = serializers.SerializerMethodField(style={"show": False}) + examples__count = serializers.SerializerMethodField(style={"show": False}) + evaluate_languages_count = serializers.SerializerMethodField(style={"show": False}) + absolute_url = serializers.SerializerMethodField(style={"show": False}) + authorization = serializers.SerializerMethodField(style={"show": False}) + request_authorization = serializers.SerializerMethodField(style={"show": False}) + available_request_authorization = serializers.SerializerMethodField(style={"show": False}) + entities = serializers.SerializerMethodField(style={"show": False}) + nlp_server = serializers.SerializerMethodField(style={"show": False}) def get_nlp_server(self, obj): if obj.nlp_server: From 2f5ae11ef5138d90b247ae69f46ad4d0958bd81d Mon Sep 17 00:00:00 2001 From: Daniel Yohan Date: Fri, 8 Nov 2019 22:06:33 -0300 Subject: [PATCH 207/207] Updated HelpText Analyze Char --- bothub/api/v2/repository/serializers.py | 14 +++++++++----- bothub/common/models.py | 10 +++++++++- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/bothub/api/v2/repository/serializers.py b/bothub/api/v2/repository/serializers.py index 8824b1c9..86c6f971 100644 --- a/bothub/api/v2/repository/serializers.py +++ b/bothub/api/v2/repository/serializers.py @@ -221,9 +221,7 @@ class Meta: languages_warnings = serializers.ReadOnlyField(style={"show": False}) use_language_model_featurizer = serializers.ReadOnlyField(style={"show": False}) - language = serializers.ChoiceField( - LANGUAGE_CHOICES, label=_("Language") - ) + language = serializers.ChoiceField(LANGUAGE_CHOICES, label=_("Language")) owner = serializers.PrimaryKeyRelatedField(read_only=True, style={"show": False}) owner__nickname = serializers.SlugRelatedField( source="owner", slug_field="nickname", read_only=True, style={"show": False} @@ -231,7 +229,11 @@ class Meta: intents = serializers.SerializerMethodField(style={"show": False}) intents_list = serializers.SerializerMethodField(style={"show": False}) categories_list = serializers.SlugRelatedField( - source="categories", slug_field="name", many=True, read_only=True, style={"show": False} + source="categories", + slug_field="name", + many=True, + read_only=True, + style={"show": False}, ) categories = serializers.ManyRelatedField( child_relation=serializers.PrimaryKeyRelatedField( @@ -249,7 +251,9 @@ class Meta: absolute_url = serializers.SerializerMethodField(style={"show": False}) authorization = serializers.SerializerMethodField(style={"show": False}) request_authorization = serializers.SerializerMethodField(style={"show": False}) - available_request_authorization = serializers.SerializerMethodField(style={"show": False}) + available_request_authorization = serializers.SerializerMethodField( + style={"show": False} + ) entities = serializers.SerializerMethodField(style={"show": False}) nlp_server = serializers.SerializerMethodField(style={"show": False}) diff --git a/bothub/common/models.py b/bothub/common/models.py index 07d40b84..580adfd0 100644 --- a/bothub/common/models.py +++ b/bothub/common/models.py @@ -148,7 +148,15 @@ class Meta: ), default=False, ) - use_analyze_char = models.BooleanField(_("Use analyze char"), default=False) + use_analyze_char = models.BooleanField( + _("Use analyze char"), + help_text=_( + "When selected, the algorithm will learn the patterns of " + + "individual characters instead of whole words. " + + "This approach works better for some languages." + ), + default=False, + ) categories = models.ManyToManyField( RepositoryCategory, help_text=CATEGORIES_HELP_TEXT )