From e81bf94dc1840a605b14fa57bf3b40e0efc0452c Mon Sep 17 00:00:00 2001 From: jedi Date: Thu, 18 Jul 2024 20:32:31 +0200 Subject: [PATCH] stash --- core/mail/tests/v2/test_mails.py | 2 +- core/tickets/api_v2.py | 37 +++++++++++++++++++++++---- core/tickets/serializers.py | 11 ++++++++ core/tickets/tests/v2/test_tickets.py | 23 +++++++++++++++-- 4 files changed, 65 insertions(+), 8 deletions(-) diff --git a/core/mail/tests/v2/test_mails.py b/core/mail/tests/v2/test_mails.py index ac03bac..3df56ca 100644 --- a/core/mail/tests/v2/test_mails.py +++ b/core/mail/tests/v2/test_mails.py @@ -760,7 +760,6 @@ dGVzdGltYWdl response = self.client.post(f'/api/2/tickets/{issue_thread.id}/reply/', { 'message': 'test' }) - aiosmtplib.send.assert_called_once() self.assertEqual(response.status_code, 201) self.assertEqual(5, len(Email.objects.all())) self.assertEqual(5, len(Email.objects.filter(issue_thread=issue_thread))) @@ -776,6 +775,7 @@ dGVzdGltYWdl self.assertEqual('test subject', IssueThread.objects.all()[0].name) self.assertEqual('pending_new', IssueThread.objects.all()[0].state) self.assertEqual(None, IssueThread.objects.all()[0].assigned_to) + aiosmtplib.send.assert_called_once() def test_mail_4byte_unicode_emoji(self): from aiosmtpd.smtp import Envelope diff --git a/core/tickets/api_v2.py b/core/tickets/api_v2.py index 319a047..479df76 100644 --- a/core/tickets/api_v2.py +++ b/core/tickets/api_v2.py @@ -1,4 +1,5 @@ import logging +from base64 import b64decode from django.urls import re_path from django.contrib.auth.decorators import permission_required @@ -10,11 +11,12 @@ from asgiref.sync import async_to_sync from channels.layers import get_channel_layer from core.settings import MAIL_DOMAIN +from inventory.models import Event from mail.models import Email from mail.protocol import send_smtp, make_reply, collect_references from notify_sessions.models import SystemEvent from tickets.models import IssueThread, Comment, STATE_CHOICES, ShippingVoucher -from tickets.serializers import IssueSerializer, CommentSerializer, ShippingVoucherSerializer +from tickets.serializers import IssueSerializer, CommentSerializer, ShippingVoucherSerializer, SearchResultSerializer class IssueViewSet(viewsets.ModelViewSet): @@ -60,7 +62,7 @@ def reply(request, pk): @api_view(['POST']) @permission_classes([IsAuthenticated]) @permission_required('tickets.add_issuethread_manual', raise_exception=True) -def manual_ticket(request): +def manual_ticket(request, event_slug): if 'name' not in request.data: return Response({'status': 'error', 'message': 'missing name'}, status=status.HTTP_400_BAD_REQUEST) if 'sender' not in request.data: @@ -121,14 +123,39 @@ def add_comment(request, pk): return Response(CommentSerializer(comment).data, status=status.HTTP_201_CREATED) +def filter_issues(issues, query): + query_tokens = query.split(' ') + for issue in issues: + value = 0 + for token in query_tokens: + if token in issue.description: + value += 1 + if value > 0: + yield {'search_score': value, 'issue': issue} + + +@api_view(['GET']) +@permission_classes([]) +# @permission_classes([IsAuthenticated]) +# @permission_required('view_item', raise_exception=True) +def search_issues(request, event_slug, query): + try: + event = Event.objects.get(slug=event_slug) + items = filter_issues(IssueThread.objects.filter(event=event), b64decode(query).decode('utf-8')) + return Response(SearchResultSerializer(items, many=True).data) + except Event.DoesNotExist: + return Response(status=404) + + router = routers.SimpleRouter() router.register(r'tickets', IssueViewSet, basename='issues') -#router.register(r'comments', CommentViewSet, basename='comments') +# router.register(r'comments', CommentViewSet, basename='comments') router.register(r'shipping_vouchers', ShippingVoucherViewSet, basename='shipping_vouchers') urlpatterns = ([ + re_path(r'tickets/states/$', get_available_states, name='get_available_states'), re_path(r'^tickets/(?P\d+)/reply/$', reply, name='reply'), re_path(r'^tickets/(?P\d+)/comment/$', add_comment, name='add_comment'), - re_path(r'^tickets/manual/$', manual_ticket, name='manual_ticket'), - re_path(r'^tickets/states/$', get_available_states, name='get_available_states'), + re_path(r'^(?P[\w-]+)/tickets/manual/$', manual_ticket, name='manual_ticket'), + re_path(r'^(?P[\w-]+)/tickets/(?P.+)/$', search_issues, name='search_issues'), ] + router.urls) diff --git a/core/tickets/serializers.py b/core/tickets/serializers.py index 3d850c4..76561f6 100644 --- a/core/tickets/serializers.py +++ b/core/tickets/serializers.py @@ -134,3 +134,14 @@ class IssueSerializer(serializers.ModelSerializer): def get_queryset(self): return IssueThread.objects.all().order_by('-last_activity') + + +class SearchResultSerializer(serializers.Serializer): + search_score = serializers.IntegerField() + item = IssueSerializer() + + def to_representation(self, instance): + return {**IssueSerializer(instance['item']).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 0fea3dc..dae1755 100644 --- a/core/tickets/tests/v2/test_tickets.py +++ b/core/tickets/tests/v2/test_tickets.py @@ -8,6 +8,8 @@ from tickets.models import IssueThread, StateChange, Comment from django.contrib.auth.models import Permission from knox.models import AuthToken +from base64 import b64encode + class IssueApiTest(TestCase): @@ -230,7 +232,7 @@ class IssueApiTest(TestCase): self.assertEqual(file2.hash, response.json()[0]['timeline'][1]['attachments'][1]['hash']) def test_manual_creation(self): - response = self.client.post('/api/2/tickets/manual/', + response = self.client.post('/api/2/evt/tickets/manual/', {'name': 'test issue', 'sender': 'test', 'recipient': 'test', 'body': 'test'}, content_type='application/json') self.assertEqual(response.status_code, 201) @@ -247,7 +249,7 @@ class IssueApiTest(TestCase): self.assertEqual(timeline[1]['subject'], 'test issue') self.assertEqual(timeline[1]['body'], 'test') - #def test_post_comment(self): + # def test_post_comment(self): # issue = IssueThread.objects.create( # name="test issue", # ) @@ -315,3 +317,20 @@ class IssueApiTest(TestCase): self.assertEqual('pending_new', timeline[0]['state']) self.assertEqual('assignment', timeline[1]['type']) self.assertEqual(self.user.username, timeline[1]['assigned_to']) + + +class IssueSearchTest(TestCase): + + def setUp(self): + super().setUp() + self.user = ExtendedUser.objects.create_user('testuser', 'test', 'test') + self.user.user_permissions.add(*Permission.objects.all()) + self.user.save() + self.token = AuthToken.objects.create(user=self.user) + self.client = Client(headers={'Authorization': 'Token ' + self.token[1]}) + + def test_search(self): + search_query = b64encode(b'abc').decode('utf-8') + response = self.client.get(f'/api/2/evt/tickets/{search_query}/') + self.assertEqual(200, response.status_code) + self.assertEqual([], response.json())