From ea3aaddb246eaebc7455dffd8183a695e4351172 Mon Sep 17 00:00:00 2001 From: jedi Date: Wed, 8 Jan 2025 23:23:38 +0100 Subject: [PATCH] fix bug in tickets search api and add tests --- core/tickets/api_v2.py | 33 ++++++++++-- core/tickets/serializers.py | 4 +- core/tickets/tests/v2/test_tickets.py | 74 ++++++++++++++++++++++++++- 3 files changed, 104 insertions(+), 7 deletions(-) diff --git a/core/tickets/api_v2.py b/core/tickets/api_v2.py index 99dc008..1020c71 100644 --- a/core/tickets/api_v2.py +++ b/core/tickets/api_v2.py @@ -143,12 +143,36 @@ def add_comment(request, pk): def filter_issues(issues, query): - query_tokens = query.split(' ') + query_tokens = query.lower().split(' ') for issue in issues: value = 0 + if issue.short_uuid() in query: + value += 10 + if "T#" + str(issue.id) in query: + value += 10 + elif "#" + str(issue.id) in query: + value += 9 + for item in issue.related_items: + if "I#" + str(item.id) in query: + value += 8 + elif "#" + str(item.id) in query: + value += 5 + for token in query_tokens: + if token in item.description.lower(): + value += 1 for token in query_tokens: - if token in issue.description: + if token in issue.name.lower(): value += 1 + for comment in issue.comments.all(): + for token in query_tokens: + if token in comment.comment.lower(): + value += 1 + for email in issue.emails.all(): + for token in query_tokens: + if token in email.subject.lower(): + value += 1 + if token in email.body.lower(): + value += 1 if value > 0: yield {'search_score': value, 'issue': issue} @@ -160,7 +184,10 @@ def search_issues(request, event_slug, query): event = Event.objects.get(slug=event_slug) if not request.user.has_event_perm(event, 'view_issuethread'): return Response(status=403) - items = filter_issues(IssueThread.objects.filter(event=event), b64decode(query).decode('utf-8')) + serializer = IssueSerializer() + queryset = IssueThread.objects.filter(event=event) + items = filter_issues(queryset.prefetch_related(*serializer.Meta.prefetch_related_fields), + b64decode(query).decode('utf-8')) return Response(SearchResultSerializer(items, many=True).data) except Event.DoesNotExist: return Response(status=404) diff --git a/core/tickets/serializers.py b/core/tickets/serializers.py index 50cdb72..a236d61 100644 --- a/core/tickets/serializers.py +++ b/core/tickets/serializers.py @@ -139,10 +139,10 @@ class IssueSerializer(BasicIssueSerializer): class SearchResultSerializer(serializers.Serializer): search_score = serializers.IntegerField() - item = IssueSerializer() + issue = IssueSerializer() def to_representation(self, instance): - return {**IssueSerializer(instance['item']).data, 'search_score': instance['search_score']} + return {**IssueSerializer(instance['issue']).data, 'search_score': instance['search_score']} class Meta: model = IssueThread diff --git a/core/tickets/tests/v2/test_tickets.py b/core/tickets/tests/v2/test_tickets.py index 9720625..4e3d83b 100644 --- a/core/tickets/tests/v2/test_tickets.py +++ b/core/tickets/tests/v2/test_tickets.py @@ -383,15 +383,85 @@ class IssueSearchTest(TestCase): def setUp(self): super().setUp() - self.event = Event.objects.create(slug='EVENT', name='Event') self.user = ExtendedUser.objects.create_user('testuser', 'test', 'test') self.user.user_permissions.add(*Permission.objects.all()) self.user.save() + self.event = Event.objects.create(slug='EVENT', name='Event') + self.box = Container.objects.create(name='box1') + self.item = Item.objects.create(container=self.box, description="foo", event=self.event) self.token = AuthToken.objects.create(user=self.user) self.client = Client(headers={'Authorization': 'Token ' + self.token[1]}) - def test_search(self): + def test_search_empty_result(self): search_query = b64encode(b'abc').decode('utf-8') response = self.client.get(f'/api/2/{self.event.slug}/tickets/{search_query}/') self.assertEqual(200, response.status_code) self.assertEqual([], response.json()) + + def test_search(self): + now = datetime.now() + issue = IssueThread.objects.create( + name="test issue Abc", + event=self.event, + ) + mail1 = Email.objects.create( + subject='test', + body='test aBc', + sender='test', + recipient='test', + issue_thread=issue, + timestamp=now, + ) + mail2 = Email.objects.create( + subject='test', + body='test', + sender='test', + recipient='test', + issue_thread=issue, + in_reply_to=mail1.reference, + timestamp=now + timedelta(seconds=2), + ) + assignment = Assignment.objects.create( + issue_thread=issue, + assigned_to=self.user, + timestamp=now + timedelta(seconds=3), + ) + comment = Comment.objects.create( + issue_thread=issue, + comment="test deF", + timestamp=now + timedelta(seconds=4), + ) + match = ItemRelation.objects.create( + issue_thread=issue, + item=self.item, + timestamp=now + timedelta(seconds=5), + ) + search_query = b64encode(b'abC').decode('utf-8') + response = self.client.get(f'/api/2/{self.event.slug}/tickets/{search_query}/') + self.assertEqual(200, response.status_code) + self.assertEqual(1, len(response.json())) + self.assertEqual(issue.id, response.json()[0]['id']) + score2 = response.json()[0]['search_score'] + + search_query = b64encode(b'dEf').decode('utf-8') + response = self.client.get(f'/api/2/{self.event.slug}/tickets/{search_query}/') + self.assertEqual(200, response.status_code) + self.assertEqual(1, len(response.json())) + self.assertEqual(issue.id, response.json()[0]['id']) + score1 = response.json()[0]['search_score'] + + search_query = b64encode(b'ghi').decode('utf-8') + response = self.client.get(f'/api/2/{self.event.slug}/tickets/{search_query}/') + self.assertEqual(200, response.status_code) + self.assertEqual(0, len(response.json())) + + search_query = b64encode(b'Abc def').decode('utf-8') + response = self.client.get(f'/api/2/{self.event.slug}/tickets/{search_query}/') + self.assertEqual(200, response.status_code) + self.assertEqual(1, len(response.json())) + self.assertEqual(issue.id, response.json()[0]['id']) + score3 = response.json()[0]['search_score'] + + self.assertGreater(score3, score2) + self.assertGreater(score2, score1) + self.assertGreater(score1, 0)