# welco - multichannel request processing # Copyright (C) 2018 Entr'ouvert # # This program is free software: you can redistribute it and/or modify it # under the terms of the GNU Affero General Public License as published # by the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . import json import logging from django import template from django.contrib import messages from django.contrib.auth.decorators import login_required from django.contrib.contenttypes.models import ContentType from django.db.transaction import atomic from django.http import HttpResponse, HttpResponseRedirect from django.template import RequestContext from django.urls import reverse from django.utils.translation import ugettext_lazy as _ from django.views.decorators.csrf import csrf_exempt from django.views.generic import TemplateView from rest_framework import authentication, permissions, serializers, status from rest_framework.generics import GenericAPIView from rest_framework.response import Response from welco.utils import response_for_json from .forms import MailQualificationForm from .models import Mail from .utils import MaarchError, get_maarch logger = logging.getLogger(__name__) def viewer(request, *args, **kwargs): if not 'file' in request.GET: return HttpResponseRedirect('?file=') body = template.loader.get_template('welco/mail_viewer.html').render(request=request) return HttpResponse(body) class Feeder(TemplateView): template_name = 'welco/mail_feeder.html' def post(self, request): for upload in request.FILES.getlist('mail'): mail = Mail(content=upload) mail.save() messages.info(request, _('%d files uploaded successfully.') % len(request.FILES.getlist('mail'))) return HttpResponseRedirect(reverse('mail-feeder')) feeder = login_required(csrf_exempt(Feeder.as_view())) class Home: source_key = 'mail' display_filter = True allow_reject = True def __init__(self, request, **kwargs): self.request = request self.kwargs = kwargs def get_queryset(self): return Mail.objects.exclude(status__startswith='done-') def get_template(self): return 'welco/mail_home.html' def render(self): context = {} context['mails'] = self.get_queryset().order_by('creation_timestamp') context['source_type'] = ContentType.objects.get_for_model(Mail) context['form'] = MailQualificationForm() context['source_form_url'] = Mail.get_qualification_form_submit_url() if self.allow_reject: context['reject_url'] = reverse('mail-reject') context['display_filter'] = self.display_filter tmpl = template.loader.get_template(self.get_template()) return tmpl.render(context, request=self.request) @csrf_exempt def qualification_save(request, *args, **kwargs): mail = Mail.objects.get(id=request.POST['source_pk']) form = MailQualificationForm(request.POST) if form.is_valid(): mail.post_date = form.cleaned_data['post_date'] mail.registered_mail_number = form.cleaned_data['registered_mail_number'] mail.reference = form.cleaned_data['reference'] mail.subject = form.cleaned_data['subject'] mail.save() return HttpResponseRedirect( reverse('qualif-zone') + '?source_type=%s&source_pk=%s' % (request.POST['source_type'], request.POST['source_pk']) ) class EditNote(TemplateView): template_name = 'welco/mail_edit_note.html' def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context['mail'] = Mail.objects.get(id=self.request.GET['mail']) return context def post(self, request, *args, **kwargs): mail = Mail.objects.get(id=self.request.GET['mail']) mail.note = self.request.POST['note'] mail.save() return HttpResponse(json.dumps({'result': 'ok'})) edit_note = login_required(csrf_exempt(EditNote.as_view())) @login_required def note(request, *args, **kwargs): mail = Mail.objects.get(id=kwargs['pk']) if not mail.note: mail.note = '+' return HttpResponse(mail.html_note()) @login_required @csrf_exempt def reject(request, *args, **kwargs): maarch = get_maarch() mail = Mail.objects.filter(id=request.POST['source_pk']).first() if mail: try: with atomic(): if maarch and mail.external_id and mail.external_id.startswith('maarch-'): mail_pk = mail.external_id.split('-', 1)[1] maarch.set_grc_refused_status(mail_pk) mail.delete() except Exception: logger.exception('rejection request to maarch failed') messages.error(request, _('Rejection request to Maarch failed')) return HttpResponse() @login_required def mail_count(request, *args, **kwargs): count = Mail.objects.exclude(status__startswith='done-').count() return response_for_json(request, {'count': count}) class NotificationSerializer(serializers.Serializer): mail_id = serializers.CharField() content = serializers.CharField() class MailResponseAPIView(GenericAPIView): permission_classes = (permissions.IsAuthenticated,) serializer_class = NotificationSerializer def post(self, request, *args, **kwargs): serializer = self.get_serializer(data=request.data) if not serializer.is_valid(): response = {'err': 1, 'err_desc': serializer.errors} return Response(response, status.HTTP_400_BAD_REQUEST) mail_id = serializer.validated_data['mail_id'] content = serializer.validated_data['content'] # for now, we only support maarch if not mail_id.startswith('maarch-'): response = {'err': 1, 'err_desc': 'only maarch is supported'} return Response(response) mail = Mail.objects.filter(external_id=mail_id).first() if not mail: response = {'err': 1, 'err_desc': 'unknown mail_id'} return Response(response, status.HTTP_404_NOT_FOUND) return self.maarch_response(mail, content) def maarch_response(self, mail, content): maarch = get_maarch() if not maarch: return Response({'err': 1, 'err_desc': 'maarch is unconfigured'}) mail_pk = int(mail.external_id.split('-', 1)[1]) try: maarch.set_grc_response_status(mail_pk, content) except MaarchError as e: return Response({'err': 1, 'err_desc': str(e)}) return Response({'err': 0}) mail_response = MailResponseAPIView.as_view()