import logging from django.urls import path from django.contrib.auth.decorators import permission_required from rest_framework import routers, viewsets, serializers, status 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 core.settings import MAIL_DOMAIN from mail.models import Email from mail.protocol import send_smtp, make_reply, collect_references from tickets.models import IssueThread class IssueSerializer(serializers.ModelSerializer): timeline = serializers.SerializerMethodField() class Meta: model = IssueThread fields = ('id', 'timeline', 'name', 'state', 'assigned_to', 'last_activity') read_only_fields = ('id', 'timeline', 'last_activity') @staticmethod def get_timeline(obj): timeline = [] for comment in obj.comments.all(): timeline.append({ 'type': 'comment', 'id': comment.id, 'timestamp': comment.timestamp, 'comment': comment.comment, }) for state_change in obj.state_changes.all(): timeline.append({ 'type': 'state', 'id': state_change.id, 'timestamp': state_change.timestamp, 'state': state_change.state, }) for email in obj.emails.all(): timeline.append({ 'type': 'mail', 'id': email.id, 'timestamp': email.timestamp, 'sender': email.sender, 'recipient': email.recipient, 'subject': email.subject, 'body': email.body, }) return sorted(timeline, key=lambda x: x['timestamp']) class IssueViewSet(viewsets.ModelViewSet): serializer_class = IssueSerializer queryset = IssueThread.objects.all() @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) most_recent = Email.objects.filter(issue_thread=issue, recipient__endswith='@' + MAIL_DOMAIN).order_by( '-timestamp').first() mail = Email.objects.create( issue_thread=issue, sender=most_recent.recipient, recipient=most_recent.sender, subject=f'Re: {most_recent.subject}', body=request.data['message'], in_reply_to=most_recent.reference, ) log = logging.getLogger('mail.log') async_to_sync(send_smtp)(make_reply(mail, references), log) return Response({'status': 'ok'}, status=status.HTTP_201_CREATED) router = routers.SimpleRouter() router.register(r'tickets', IssueViewSet, basename='issues') urlpatterns = router.urls + [ path('tickets//reply/', reply, name='reply'), ]