diff --git a/bothub/api/v2/repository/filters.py b/bothub/api/v2/repository/filters.py new file mode 100644 index 00000000..d43f0624 --- /dev/null +++ b/bothub/api/v2/repository/filters.py @@ -0,0 +1,12 @@ +from django_filters import rest_framework as filters + +from bothub.common.models import Repository + + +class RepositoriesFilter(filters.FilterSet): + class Meta: + model = Repository + fields = [ + 'name', + 'categories', + ] diff --git a/bothub/api/v2/repository/serializers.py b/bothub/api/v2/repository/serializers.py index 8ab46d3b..02f0b8eb 100644 --- a/bothub/api/v2/repository/serializers.py +++ b/bothub/api/v2/repository/serializers.py @@ -219,3 +219,31 @@ def get_available_request_authorization(self, obj): return False except RequestRepositoryAuthorization.DoesNotExist: return True + + +class ShortRepositorySerializer(serializers.ModelSerializer): + class Meta: + model = Repository + fields = [ + 'uuid', + 'name', + 'slug', + 'description', + 'is_private', + 'language', + 'available_languages', + 'created_at', + 'owner', + 'owner__nickname', + 'absolute_url', + ] + read_only = fields + + owner__nickname = serializers.SlugRelatedField( + source='owner', + slug_field='nickname', + read_only=True) + absolute_url = serializers.SerializerMethodField() + + def get_absolute_url(self, obj): + return obj.get_absolute_url() diff --git a/bothub/api/v2/repository/tests.py b/bothub/api/v2/repository/tests.py index 59499172..f157f420 100644 --- a/bothub/api/v2/repository/tests.py +++ b/bothub/api/v2/repository/tests.py @@ -14,6 +14,7 @@ from ..tests.utils import create_user_and_token from .views import RepositoryViewSet +from .views import RepositoriesViewSet from .serializers import RepositorySerializer @@ -366,7 +367,7 @@ def test_false_when_request(self): self.assertFalse(available_request_authorization) -class IntentsInRepositorySerializer(TestCase): +class IntentsInRepositorySerializerTestCase(TestCase): def setUp(self): self.owner, self.owner_token = create_user_and_token('owner') @@ -397,3 +398,79 @@ def test_example_deleted(self): repository_data = RepositorySerializer(self.repository).data 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.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, + ) + ) + + def request(self, data={}, token=None): + authorization_header = { + 'HTTP_AUTHORIZATION': 'Token {}'.format(token.key), + } if token else {} + request = self.factory.get( + '/api/v2/repositories/', + data, + **authorization_header, + ) + response = RepositoriesViewSet.as_view({'get': 'list'})(request) + response.render() + content_data = json.loads(response.content) + 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, + ) + + 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, + ) + + 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, + ) diff --git a/bothub/api/v2/repository/views.py b/bothub/api/v2/repository/views.py index e714e011..557b493d 100644 --- a/bothub/api/v2/repository/views.py +++ b/bothub/api/v2/repository/views.py @@ -1,12 +1,16 @@ from rest_framework.viewsets import GenericViewSet from rest_framework import mixins from rest_framework.permissions import IsAuthenticatedOrReadOnly +from django_filters.rest_framework import DjangoFilterBackend +from rest_framework.filters import SearchFilter from bothub.common.models import Repository from ..metadata import Metadata from .serializers import RepositorySerializer +from .serializers import ShortRepositorySerializer from .permissions import RepositoryPermission +from .filters import RepositoriesFilter class RepositoryViewSet( @@ -26,3 +30,23 @@ class RepositoryViewSet( RepositoryPermission, ] metadata_class = Metadata + + +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', + ] diff --git a/bothub/api/v2/routers.py b/bothub/api/v2/routers.py index fb0a402b..03e294bf 100644 --- a/bothub/api/v2/routers.py +++ b/bothub/api/v2/routers.py @@ -1,9 +1,11 @@ from rest_framework import routers from .repository.views import RepositoryViewSet +from .repository.views import RepositoriesViewSet from .examples.views import ExamplesViewSet router = routers.SimpleRouter() router.register('repository', RepositoryViewSet) +router.register('repositories', RepositoriesViewSet) router.register('examples', ExamplesViewSet)