2024-01-07 20:18:42 +00:00
|
|
|
import logging
|
|
|
|
|
|
|
|
from django.urls import re_path
|
|
|
|
from django.contrib.auth.decorators import permission_required
|
2024-01-22 16:21:22 +00:00
|
|
|
from rest_framework import routers, viewsets, status
|
2024-01-07 20:18:42 +00:00
|
|
|
from rest_framework.decorators import api_view, permission_classes
|
|
|
|
from rest_framework.permissions import IsAuthenticated
|
|
|
|
from rest_framework.response import Response
|
|
|
|
from asgiref.sync import async_to_sync
|
|
|
|
from channels.layers import get_channel_layer
|
|
|
|
|
|
|
|
from core.settings import MAIL_DOMAIN
|
|
|
|
from mail.models import Email
|
|
|
|
from mail.protocol import send_smtp, make_reply, collect_references
|
|
|
|
from notify_sessions.models import SystemEvent
|
2024-06-15 16:04:43 +00:00
|
|
|
from tickets.models import IssueThread, Comment, STATE_CHOICES, ShippingCode
|
|
|
|
from tickets.serializers import IssueSerializer, CommentSerializer, ShippingCodeSerializer
|
2024-01-10 19:03:25 +00:00
|
|
|
|
2024-01-07 20:18:42 +00:00
|
|
|
|
|
|
|
class IssueViewSet(viewsets.ModelViewSet):
|
|
|
|
serializer_class = IssueSerializer
|
|
|
|
queryset = IssueThread.objects.all()
|
|
|
|
|
|
|
|
|
2024-06-15 16:04:43 +00:00
|
|
|
class ShippingCodeViewSet(viewsets.ModelViewSet):
|
|
|
|
serializer_class = ShippingCodeSerializer
|
|
|
|
queryset = ShippingCode.objects.all()
|
|
|
|
|
|
|
|
|
2024-01-07 20:18:42 +00:00
|
|
|
@api_view(['POST'])
|
|
|
|
@permission_classes([IsAuthenticated])
|
|
|
|
@permission_required('tickets.add_issuethread', raise_exception=True)
|
|
|
|
def reply(request, pk):
|
|
|
|
issue = IssueThread.objects.get(pk=pk)
|
|
|
|
# email = issue.reply(request.data['body']) # TODO evaluate if this is a useful abstraction
|
|
|
|
references = collect_references(issue)
|
2024-01-15 21:00:03 +00:00
|
|
|
first_mail = Email.objects.filter(issue_thread=issue, recipient__endswith='@' + MAIL_DOMAIN).order_by(
|
|
|
|
'timestamp').first()
|
|
|
|
if not first_mail:
|
2024-01-22 16:21:22 +00:00
|
|
|
return Response({'status': 'error', 'message': 'no previous mail found, reply would not make sense.'},
|
|
|
|
status=status.HTTP_400_BAD_REQUEST)
|
2024-01-07 20:18:42 +00:00
|
|
|
mail = Email.objects.create(
|
|
|
|
issue_thread=issue,
|
2024-01-15 21:00:03 +00:00
|
|
|
sender=first_mail.recipient,
|
|
|
|
recipient=first_mail.sender,
|
|
|
|
subject=f'Re: {issue.name} [#{issue.short_uuid()}]',
|
2024-01-07 20:18:42 +00:00
|
|
|
body=request.data['message'],
|
2024-01-15 21:00:03 +00:00
|
|
|
in_reply_to=first_mail.reference,
|
2024-01-07 20:18:42 +00:00
|
|
|
)
|
2024-06-22 23:20:13 +00:00
|
|
|
async_to_sync(send_smtp)(make_reply(mail, references))
|
2024-01-07 20:18:42 +00:00
|
|
|
|
|
|
|
return Response({'status': 'ok'}, status=status.HTTP_201_CREATED)
|
|
|
|
|
|
|
|
|
|
|
|
@api_view(['POST'])
|
|
|
|
@permission_classes([IsAuthenticated])
|
|
|
|
@permission_required('tickets.add_issuethread_manual', raise_exception=True)
|
|
|
|
def manual_ticket(request):
|
|
|
|
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:
|
|
|
|
return Response({'status': 'error', 'message': 'missing sender'}, status=status.HTTP_400_BAD_REQUEST)
|
|
|
|
if 'recipient' not in request.data:
|
|
|
|
return Response({'status': 'error', 'message': 'missing recipient'}, status=status.HTTP_400_BAD_REQUEST)
|
|
|
|
if 'body' not in request.data:
|
|
|
|
return Response({'status': 'error', 'message': 'missing body'}, status=status.HTTP_400_BAD_REQUEST)
|
|
|
|
|
|
|
|
issue = IssueThread.objects.create(
|
|
|
|
name=request.data['name'],
|
|
|
|
manually_created=True,
|
|
|
|
)
|
|
|
|
email = Email.objects.create(
|
|
|
|
issue_thread=issue,
|
|
|
|
sender=request.data['sender'],
|
|
|
|
recipient=request.data['recipient'],
|
|
|
|
subject=request.data['name'],
|
|
|
|
body=request.data['body'],
|
|
|
|
)
|
|
|
|
systemevent = SystemEvent.objects.create(type='email received', reference=email.id)
|
|
|
|
channel_layer = get_channel_layer()
|
|
|
|
async_to_sync(channel_layer.group_send)(
|
|
|
|
'general', {"type": "generic.event", "name": "send_message_to_frontend", "event_id": systemevent.id,
|
|
|
|
"message": "email received"}
|
|
|
|
)
|
|
|
|
|
|
|
|
return Response(IssueSerializer(issue).data, status=status.HTTP_201_CREATED)
|
|
|
|
|
|
|
|
|
2023-12-28 20:08:26 +00:00
|
|
|
@api_view(['GET'])
|
|
|
|
@permission_classes([IsAuthenticated])
|
|
|
|
def get_available_states(request):
|
|
|
|
def get_state_choices():
|
|
|
|
for state in STATE_CHOICES:
|
|
|
|
yield {'value': list(state)[0], 'text': list(state)[1]}
|
2023-12-30 17:34:35 +00:00
|
|
|
|
2023-12-28 20:08:26 +00:00
|
|
|
return Response(get_state_choices())
|
|
|
|
|
|
|
|
|
2024-01-13 00:40:37 +00:00
|
|
|
@api_view(['POST'])
|
|
|
|
@permission_classes([IsAuthenticated])
|
|
|
|
@permission_required('tickets.add_comment', raise_exception=True)
|
|
|
|
def add_comment(request, pk):
|
|
|
|
issue = IssueThread.objects.get(pk=pk)
|
|
|
|
if 'comment' not in request.data or request.data['comment'] == '':
|
|
|
|
return Response({'status': 'error', 'message': 'missing comment'}, status=status.HTTP_400_BAD_REQUEST)
|
|
|
|
comment = Comment.objects.create(
|
|
|
|
issue_thread=issue,
|
|
|
|
comment=request.data['comment'],
|
|
|
|
)
|
|
|
|
systemevent = SystemEvent.objects.create(type='comment added', reference=comment.id)
|
|
|
|
channel_layer = get_channel_layer()
|
|
|
|
async_to_sync(channel_layer.group_send)(
|
|
|
|
'general', {"type": "generic.event", "name": "send_message_to_frontend", "event_id": systemevent.id,
|
|
|
|
"message": "comment added"}
|
|
|
|
)
|
|
|
|
return Response(CommentSerializer(comment).data, status=status.HTTP_201_CREATED)
|
|
|
|
|
|
|
|
|
2024-01-07 20:18:42 +00:00
|
|
|
router = routers.SimpleRouter()
|
|
|
|
router.register(r'tickets', IssueViewSet, basename='issues')
|
2024-06-15 16:04:43 +00:00
|
|
|
router.register(r'shipping_codes', ShippingCodeViewSet, basename='shipping_codes')
|
2024-01-07 20:18:42 +00:00
|
|
|
|
|
|
|
urlpatterns = ([
|
|
|
|
re_path(r'^tickets/(?P<pk>\d+)/reply/$', reply, name='reply'),
|
2024-01-13 00:40:37 +00:00
|
|
|
re_path(r'^tickets/(?P<pk>\d+)/comment/$', add_comment, name='add_comment'),
|
2024-01-07 20:18:42 +00:00
|
|
|
re_path(r'^tickets/manual/$', manual_ticket, name='manual_ticket'),
|
2023-12-28 20:08:26 +00:00
|
|
|
re_path(r'^tickets/states/$', get_available_states, name='get_available_states'),
|
2024-01-07 20:18:42 +00:00
|
|
|
] + router.urls)
|