Contact forms update.
[wolnelektury.git] / src / contact / forms.py
1 # This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
2 # Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
3 #
4 import json
5 from django.contrib.sites.models import Site
6 from django.core.exceptions import ValidationError
7 from django.core.files.uploadedfile import UploadedFile
8 from django.core.mail import send_mail, mail_managers
9 from django.core.validators import validate_email
10 from django import forms
11 from django.template.loader import render_to_string
12 from django.template import RequestContext
13 from django.urls import reverse
14 from django.utils.translation import ugettext_lazy as _
15
16
17 contact_forms = {}
18 admin_list_width = 0
19
20
21 class ContactFormMeta(forms.Form.__class__):
22     def __new__(cls, name, bases, attrs):
23         global admin_list_width
24         model = super(ContactFormMeta, cls).__new__(cls, name, bases, attrs)
25         assert model.form_tag not in contact_forms, 'Duplicate form_tag.'
26         if model.admin_list:
27             admin_list_width = max(admin_list_width, len(model.admin_list))
28         contact_forms[model.form_tag] = model
29         return model
30
31
32 class ContactForm(forms.Form, metaclass=ContactFormMeta):
33     """Subclass and define some fields."""
34
35     form_tag = None
36     form_title = _('Contact form')
37     submit_label = _('Submit')
38     admin_list = None
39     result_page = False
40
41     required_css_class = 'required'
42     # a subclass has to implement this field, but doing it here breaks the order
43     contact = NotImplemented
44
45     def save(self, request, formsets=None):
46         from .models import Attachment, Contact
47         body = {}
48         for name, value in self.cleaned_data.items():
49             if not isinstance(value, UploadedFile) and name != 'contact':
50                 body[name] = value
51
52         for formset in formsets or []:
53             for f in formset.forms:
54                 sub_body = {}
55                 for name, value in f.cleaned_data.items():
56                     if not isinstance(value, UploadedFile):
57                         sub_body[name] = value
58                 if sub_body:
59                     body.setdefault(f.form_tag, []).append(sub_body)
60
61         contact = Contact.objects.create(
62             body=json.dumps(body),
63             ip=request.META['REMOTE_ADDR'],
64             contact=self.cleaned_data['contact'],
65             form_tag=self.form_tag)
66         for name, value in self.cleaned_data.items():
67             if isinstance(value, UploadedFile):
68                 attachment = Attachment(contact=contact, tag=name)
69                 attachment.file.save(value.name, value)
70                 attachment.save()
71
72         site = Site.objects.get_current()
73         dictionary = {
74             'form_tag': self.form_tag,
75             'site_name': getattr(self, 'site_name', site.name),
76             'site_domain': getattr(self, 'site_domain', site.domain),
77             'contact': contact,
78         }
79         mail_managers_subject = render_to_string([
80                 'contact/%s/mail_managers_subject.txt' % self.form_tag,
81                 'contact/mail_managers_subject.txt', 
82             ], dictionary, request).strip()
83         mail_managers_body = render_to_string([
84                 'contact/%s/mail_managers_body.txt' % self.form_tag,
85                 'contact/mail_managers_body.txt', 
86             ], dictionary, request)
87         mail_managers(mail_managers_subject, mail_managers_body, fail_silently=True)
88
89         try:
90             validate_email(contact.contact)
91         except ValidationError:
92             pass
93         else:
94             mail_subject = render_to_string([
95                     'contact/%s/mail_subject.txt' % self.form_tag,
96                     'contact/mail_subject.txt', 
97                 ], dictionary, request).strip()
98             if self.result_page:
99                 mail_body = render_to_string(
100                     'contact/%s/results_email.txt' % contact.form_tag,
101                     {
102                         'contact': contact,
103                         'results': self.results(contact),
104                     }, request)
105             else:
106                 mail_body = render_to_string([
107                         'contact/%s/mail_body.txt' % self.form_tag,
108                         'contact/mail_body.txt',
109                     ], dictionary, request)
110             send_mail(mail_subject, mail_body, 'no-reply@%s' % site.domain, [contact.contact], fail_silently=True)
111
112         return contact