diff --git a/core/inventory/api_v2.py b/core/inventory/api_v2.py index 030c576..86af8f3 100644 --- a/core/inventory/api_v2.py +++ b/core/inventory/api_v2.py @@ -6,7 +6,9 @@ from rest_framework.response import Response from rest_framework.permissions import IsAuthenticated from inventory.models import Event, Container, Item -from inventory.serializers import EventSerializer, ContainerSerializer, ItemSerializer +from inventory.serializers import EventSerializer, ContainerSerializer, ItemSerializer, SearchResultSerializer + +from base64 import b64decode class EventViewSet(viewsets.ModelViewSet): @@ -23,8 +25,13 @@ class ContainerViewSet(viewsets.ModelViewSet): def filter_items(items, query): query_tokens = query.split(' ') for item in items: - if all(token in item.description for token in query_tokens): - yield item + value = 0 + for token in query_tokens: + if token in item.description: + value += 1 + if value > 0: + yield {'search_score': value, 'item': item} + @api_view(['GET']) @permission_classes([]) @@ -33,8 +40,8 @@ def filter_items(items, query): def search_items(request, event_slug, query): try: event = Event.objects.get(slug=event_slug) - items = filter_items(Item.objects.filter(event=event), query) - return Response(ItemSerializer(items, many=True).data) + items = filter_items(Item.objects.filter(event=event), b64decode(query).decode('utf-8')) + return Response(SearchResultSerializer(items, many=True).data) except Event.DoesNotExist: return Response(status=404) diff --git a/core/inventory/serializers.py b/core/inventory/serializers.py index 3c0eb7e..adaf020 100644 --- a/core/inventory/serializers.py +++ b/core/inventory/serializers.py @@ -97,3 +97,14 @@ class ItemSerializer(serializers.ModelSerializer): validated_data.pop('dataImage') instance.files.add(file) return super().update(instance, validated_data) + + +class SearchResultSerializer(serializers.Serializer): + search_score = serializers.IntegerField() + item = ItemSerializer() + + def to_representation(self, instance): + return {**ItemSerializer(instance['item']).data, 'search_score': instance['search_score']} + + class Meta: + model = Item diff --git a/core/inventory/tests/v2/test_items.py b/core/inventory/tests/v2/test_items.py index a955161..5afe35c 100644 --- a/core/inventory/tests/v2/test_items.py +++ b/core/inventory/tests/v2/test_items.py @@ -7,6 +7,8 @@ from authentication.models import ExtendedUser from files.models import File from inventory.models import Event, Container, Item +from base64 import b64encode + class ItemTestCase(TestCase): @@ -169,3 +171,74 @@ class ItemTestCase(TestCase): self.assertEqual(response.status_code, 200) self.assertEqual(len(response.json()), 1) self.assertEqual(response.json()[0]['uid'], item1.uid) + + +class ItemSearchTestCase(TestCase): + + def setUp(self): + super().setUp() + self.event = Event.objects.create(slug='EVENT', name='Event') + self.box = Container.objects.create(name='BOX') + self.user = ExtendedUser.objects.create_user('testuser', 'test', 'test') + self.user.user_permissions.add(*Permission.objects.all()) + self.token = AuthToken.objects.create(user=self.user) + self.client = Client(headers={'Authorization': 'Token ' + self.token[1]}) + self.item1 = Item.objects.create(container=self.box, event=self.event, description='abc def') + self.item2 = Item.objects.create(container=self.box, event=self.event, description='def ghi') + self.item3 = Item.objects.create(container=self.box, event=self.event, description='jkl mno pqr') + self.item4 = Item.objects.create(container=self.box, event=self.event, description='stu vwx') + + def test_search(self): + search_query = b64encode(b'abc').decode('utf-8') + response = self.client.get(f'/api/2/{self.event.slug}/items/{search_query}/') + self.assertEqual(200, response.status_code) + self.assertEqual(1, len(response.json())) + self.assertEqual(self.item1.uid, response.json()[0]['uid']) + self.assertEqual('abc def', response.json()[0]['description']) + self.assertEqual('BOX', response.json()[0]['box']) + self.assertEqual(self.box.cid, response.json()[0]['cid']) + self.assertEqual(1, response.json()[0]['search_score']) + + def test_search2(self): + search_query = b64encode(b'def').decode('utf-8') + response = self.client.get(f'/api/2/{self.event.slug}/items/{search_query}/') + self.assertEqual(200, response.status_code) + self.assertEqual(2, len(response.json())) + self.assertEqual(self.item1.uid, response.json()[0]['uid']) + self.assertEqual('abc def', response.json()[0]['description']) + self.assertEqual('BOX', response.json()[0]['box']) + self.assertEqual(self.box.cid, response.json()[0]['cid']) + self.assertEqual(1, response.json()[0]['search_score']) + self.assertEqual(self.item2.uid, response.json()[1]['uid']) + self.assertEqual('def ghi', response.json()[1]['description']) + self.assertEqual('BOX', response.json()[1]['box']) + self.assertEqual(self.box.cid, response.json()[1]['cid']) + self.assertEqual(1, response.json()[0]['search_score']) + + def test_search3(self): + search_query = b64encode(b'jkl').decode('utf-8') + response = self.client.get(f'/api/2/{self.event.slug}/items/{search_query}/') + self.assertEqual(200, response.status_code) + self.assertEqual(1, len(response.json())) + self.assertEqual(self.item3.uid, response.json()[0]['uid']) + self.assertEqual('jkl mno pqr', response.json()[0]['description']) + self.assertEqual('BOX', response.json()[0]['box']) + self.assertEqual(self.box.cid, response.json()[0]['cid']) + self.assertEqual(1, response.json()[0]['search_score']) + + def test_search4(self): + search_query = b64encode(b'abc def').decode('utf-8') + response = self.client.get(f'/api/2/{self.event.slug}/items/{search_query}/') + self.assertEqual(200, response.status_code) + self.assertEqual(2, len(response.json())) + self.assertEqual(self.item1.uid, response.json()[0]['uid']) + self.assertEqual('abc def', response.json()[0]['description']) + self.assertEqual('BOX', response.json()[0]['box']) + self.assertEqual(self.box.cid, response.json()[0]['cid']) + self.assertEqual(2, response.json()[0]['search_score']) + self.assertEqual(self.item2.uid, response.json()[1]['uid']) + self.assertEqual('def ghi', response.json()[1]['description']) + self.assertEqual('BOX', response.json()[1]['box']) + self.assertEqual(self.box.cid, response.json()[1]['cid']) + self.assertEqual(1, response.json()[1]['search_score']) +