Repository: weni-ai/bothub-engine

Issue:
Validate entity chars, no special chars



Discussion:

Resolving patch:
diff --git a/bothub/api/views.py b/bothub/api/views.py
--- a/bothub/api/views.py
+++ b/bothub/api/views.py
@@ -9,6 +9,7 @@
 from rest_framework.authtoken.models import Token
 from rest_framework import status
 from rest_framework.filters import OrderingFilter
+from rest_framework.filters import SearchFilter
 from rest_framework.permissions import IsAuthenticated
 from django.utils.translation import gettext as _
 from django.db.models import Count
@@ -174,6 +175,7 @@ class RepositoriesFilter(filters.FilterSet):
     class Meta:
         model = Repository
         fields = [
+            'name',
             'categories',
         ]
 
@@ -718,6 +720,15 @@ class RepositoriesViewSet(
     serializer_class = RepositorySerializer
     queryset = Repository.objects.all().publics().order_by_relevance()
     filter_class = RepositoriesFilter
+    filter_backends = [
+        DjangoFilterBackend,
+        SearchFilter,
+    ]
+    search_fields = [
+        '$name',
+        '^name',
+        '=name',
+    ]
 
 
 class TranslationsViewSet(
diff --git a/bothub/common/models.py b/bothub/common/models.py
--- a/bothub/common/models.py
+++ b/bothub/common/models.py
@@ -8,6 +8,7 @@
 from django.utils.translation import gettext as _
 from django.utils import timezone
 from django.conf import settings
+from django.core.validators import RegexValidator, _lazy_re_compile
 
 from bothub.authentication.models import User
 
@@ -18,6 +19,15 @@
 from .exceptions import DoesNotHaveTranslation
 
 
+entity_and_intent_regex = _lazy_re_compile(r'^[-a-z0-9_]+\Z')
+validate_entity_and_intent = RegexValidator(
+    entity_and_intent_regex,
+    _('Enter a valid value consisting of lowercase letters, numbers, ' +
+        'underscores or hyphens.'),
+    'invalid'
+)
+
+
 class RepositoryCategory(models.Model):
     class Meta:
         verbose_name = _('repository category')
@@ -379,7 +389,8 @@ class Meta:
         _('intent'),
         max_length=64,
         blank=True,
-        help_text=_('Example intent reference'))
+        help_text=_('Example intent reference'),
+        validators=[validate_entity_and_intent])
     created_at = models.DateTimeField(
         _('created at'),
         auto_now_add=True)
@@ -525,7 +536,8 @@ class Meta:
     entity = models.CharField(
         _('entity'),
         max_length=64,
-        help_text=_('Entity name'))
+        help_text=_('Entity name'),
+        validators=[validate_entity_and_intent])
     created_at = models.DateTimeField(
         _('created at'),
         auto_now_add=True)
diff --git a/setup.py b/setup.py
--- a/setup.py
+++ b/setup.py
@@ -7,7 +7,7 @@
 
 setup(
     name='bothub',
-    version='1.8.5',
+    version='1.8.6',
     description='bothub',
     packages=find_packages(),
     install_requires=install_requires,


Test patch:
diff --git a/bothub/api/tests/example.py b/bothub/api/tests/example.py
--- a/bothub/api/tests/example.py
+++ b/bothub/api/tests/example.py
@@ -154,6 +154,44 @@ def test_intent_or_entity_required(self):
             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)
+
 
 class RepositoryExampleRetrieveTestCase(TestCase):
     def setUp(self):
diff --git a/bothub/api/tests/repository.py b/bothub/api/tests/repository.py
--- a/bothub/api/tests/repository.py
+++ b/bothub/api/tests/repository.py
@@ -462,9 +462,10 @@ def setUp(self):
             is_private=True)
         self.repository.categories.add(self.category)
 
-    def request(self):
+    def request(self, data={}):
         request = self.factory.get(
-            '/api/repositories/')
+            '/api/repositories/',
+            data)
         response = RepositoriesViewSet.as_view({'get': 'list'})(request)
         response.render()
         content_data = json.loads(response.content)
@@ -479,6 +480,27 @@ def test_show_just_publics(self):
             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': 'z',
+        })
+        self.assertEqual(
+            response.status_code,
+            status.HTTP_200_OK)
+        self.assertEqual(
+            content_data.get('count'),
+            0)
+
 
 class TrainRepositoryTestCase(TestCase):
     def setUp(self):