django-allauth>=0.24,<0.25
django-extensions
+# contact
+pyyaml
+
polib
django-babel
--- /dev/null
+# -*- coding: utf-8 -*-
+from django import template
+from django.core.cache import cache
+from ..models import Chunk, Attachment
+
+
+register = template.Library()
+
+
+@register.simple_tag
+def chunk(key, cache_time=0):
+ try:
+ cache_key = 'chunk_' + key
+ c = cache.get(cache_key)
+ if c is None:
+ c = Chunk.objects.get(key=key)
+ cache.set(cache_key, c, int(cache_time))
+ content = c.content
+ except Chunk.DoesNotExist:
+ n = Chunk(key=key)
+ n.save()
+ return ''
+ return content
+
+
+@register.simple_tag
+def attachment(key, cache_time=0):
+ try:
+ cache_key = 'attachment_' + key
+ c = cache.get(cache_key)
+ if c is None:
+ c = Attachment.objects.get(key=key)
+ cache.set(cache_key, c, int(cache_time))
+ return c.attachment.url
+ except Attachment.DoesNotExist:
+ return ''
--- /dev/null
+# -*- coding: utf-8 -*-
+"""
+Generic app for creating contact forms.
+
+0. Add 'contact' to your INSTALLED_APPS and include 'contact.urls' somewhere
+in your urls.py, like:
+ url(r'^contact/',
+ include('contact.urls'))
+
+1. Migrate.
+
+2. Create somewhere in your project a module with some subclasses of
+contact.forms.ContactForm, specyfing form_tag and some fields in each.
+
+3. Set CONTACT_FORMS_MODULE in your settings to point to the module.
+
+4. Link to the form with {% url 'contact_form' form_tag %}.
+
+5. Optionally override some templates in form-specific template directories
+(/contact/<form_tag>/...).
+
+6. Receive submitted forms by email and read them in admin.
+
+
+Example:
+========
+
+settings.py:
+ CONTACT_FORMS_MODULE = 'myproject.contact_forms'
+
+myproject/contact_forms.py:
+ from django import forms
+ from contact.forms import ContactForm
+ from django.utils.translation import ugettext_lazy as _
+
+ class RegistrationForm(ContactForm):
+ form_tag = 'register'
+ name = forms.CharField(label=_('Name'), max_length=128)
+ presentation = forms.FileField(label=_('Presentation'))
+
+some_template.html:
+ {% url 'contact:form' 'register' %}
+
+"""
+
+from fnpdjango.utils.app import AppSettings
+
+
+class Settings(AppSettings):
+ FORMS_MODULE = "contact_forms"
+
+
+app_settings = Settings('CONTACT')
--- /dev/null
+# -*- coding: utf-8 -*-
+import csv
+import json
+
+from django.contrib import admin
+from django.utils.translation import ugettext as _
+from django.utils.safestring import mark_safe
+from django.conf.urls import patterns, url
+from django.http import HttpResponse, Http404
+
+from wolnelektury.utils import UnicodeCSVWriter
+from .forms import contact_forms, admin_list_width
+from .models import Contact
+
+
+class ContactAdminMeta(admin.ModelAdmin.__class__):
+ def __getattr__(cls, name):
+ if name.startswith('admin_list_'):
+ return lambda self: ""
+ raise AttributeError(name)
+
+
+class ContactAdmin(admin.ModelAdmin):
+ __metaclass__ = ContactAdminMeta
+ date_hierarchy = 'created_at'
+ list_display = ['created_at', 'contact', 'form_tag'] + \
+ ["admin_list_%d" % i for i in range(admin_list_width)]
+ fields = ['form_tag', 'created_at', 'contact', 'ip']
+ readonly_fields = ['form_tag', 'created_at', 'contact', 'ip']
+ list_filter = ['form_tag']
+
+ @staticmethod
+ def admin_list(obj, nr):
+ try:
+ field_name = contact_forms[obj.form_tag].admin_list[nr]
+ except BaseException:
+ return ''
+ else:
+ return Contact.pretty_print(obj.body.get(field_name, ''), for_html=True)
+
+ def __getattr__(self, name):
+ if name.startswith('admin_list_'):
+ nr = int(name[len('admin_list_'):])
+ return lambda obj: self.admin_list(obj, nr)
+ raise AttributeError(name)
+
+ def change_view(self, request, object_id, form_url='', extra_context=None):
+ if object_id:
+ try:
+ instance = Contact.objects.get(pk=object_id)
+ assert isinstance(instance.body, dict)
+ except (Contact.DoesNotExist, AssertionError):
+ pass
+ else:
+ # Create readonly fields from the body JSON.
+ attachments = list(instance.attachment_set.all())
+ body_keys = instance.body.keys() + [a.tag for a in attachments]
+
+ # Find the original form.
+ try:
+ orig_fields = contact_forms[instance.form_tag]().fields
+ except KeyError:
+ orig_fields = {}
+
+ # Try to preserve the original order.
+ orig_keys = list(orig_fields.keys())
+ admin_keys = [key for key in orig_keys if key in body_keys] + \
+ [key for key in body_keys if key not in orig_keys]
+ admin_fields = ['body__%s' % key for key in admin_keys]
+
+ self.readonly_fields.extend(admin_fields)
+
+ self.fieldsets = [
+ (None, {'fields': self.fields}),
+ (_('Body'), {'fields': admin_fields}),
+ ]
+
+ # Create field getters for fields and attachments.
+ def attach_getter(key, value):
+ def f(self):
+ return value
+ f.short_description = orig_fields[key].label if key in orig_fields else _(key)
+ setattr(self, "body__%s" % key, f)
+
+ for k, v in instance.body.items():
+ attach_getter(k, Contact.pretty_print(v, for_html=True))
+
+ download_link = "<a href='%(url)s'>%(url)s</a>"
+ for attachment in attachments:
+ link = mark_safe(download_link % {
+ 'url': attachment.get_absolute_url()})
+ attach_getter(attachment.tag, link)
+ return super(ContactAdmin, self).change_view(
+ request, object_id, form_url=form_url, extra_context=extra_context)
+
+ def changelist_view(self, request, extra_context=None):
+ context = dict()
+ if 'form_tag' in request.GET:
+ form = contact_forms.get(request.GET['form_tag'])
+ context['extract_types'] = [
+ {'slug': 'all', 'label': _('all')},
+ {'slug': 'contacts', 'label': _('contacts')}]
+ context['extract_types'] += [type for type in getattr(form, 'extract_types', [])]
+ return super(ContactAdmin, self).changelist_view(request, extra_context=context)
+
+ def get_urls(self):
+ # urls = super(ContactAdmin, self).get_urls()
+ return patterns(
+ '',
+ url(r'^extract/(?P<form_tag>[\w-]+)/(?P<extract_type_slug>[\w-]+)/$',
+ self.admin_site.admin_view(extract_view), name='contact_extract')
+ ) + super(ContactAdmin, self).get_urls()
+
+
+def extract_view(request, form_tag, extract_type_slug):
+ contacts_by_spec = dict()
+ form = contact_forms.get(form_tag)
+ if form is None and extract_type_slug not in ('contacts', 'all'):
+ raise Http404
+
+ q = Contact.objects.filter(form_tag=form_tag)
+ at_year = request.GET.get('created_at__year')
+ at_month = request.GET.get('created_at__month')
+ if at_year:
+ q = q.filter(created_at__year=at_year)
+ if at_month:
+ q = q.filter(created_at__month=at_month)
+
+ # Segregate contacts by body key sets
+ if form:
+ orig_keys = list(form().fields.keys())
+ else:
+ orig_keys = []
+ for contact in q.all():
+ if extract_type_slug == 'contacts':
+ keys = ['contact']
+ elif extract_type_slug == 'all':
+ keys = contact.body.keys() + ['contact']
+ keys = [key for key in orig_keys if key in keys] + [key for key in keys if key not in orig_keys]
+ else:
+ keys = form.get_extract_fields(contact, extract_type_slug)
+ contacts_by_spec.setdefault(tuple(keys), []).append(contact)
+
+ response = HttpResponse(content_type='text/csv')
+ csv_writer = UnicodeCSVWriter(response)
+
+ # Generate list for each body key set
+ for keys, contacts in contacts_by_spec.items():
+ csv_writer.writerow(keys)
+ for contact in contacts:
+ if extract_type_slug == 'contacts':
+ records = [dict(contact=contact.contact)]
+ elif extract_type_slug == 'all':
+ records = [dict(contact=contact.contact, **contact.body)]
+ else:
+ records = form.get_extract_records(keys, contact, extract_type_slug)
+
+ for record in records:
+ for key in keys:
+ if key not in record:
+ record[key] = ''
+ if isinstance(record[key], basestring):
+ pass
+ elif isinstance(record[key], bool):
+ record[key] = 'tak' if record[key] else 'nie'
+ elif isinstance(record[key], (list, tuple)) and all(isinstance(v, basestring) for v in record[key]):
+ record[key] = ', '.join(record[key])
+ else:
+ record[key] = json.dumps(record[key])
+
+ csv_writer.writerow([record[key] for key in keys])
+ csv_writer.writerow([])
+
+ response['Content-Disposition'] = 'attachment; filename="kontakt.csv"'
+ return response
+
+admin.site.register(Contact, ContactAdmin)
--- /dev/null
+# -*- coding: utf-8 -*-
+# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
+from django import forms
+from .widgets import HeaderWidget
+
+
+class HeaderField(forms.CharField):
+ def __init__(self, required=False, widget=None, *args, **kwargs):
+ if widget is None:
+ widget = HeaderWidget
+ super(HeaderField, self).__init__(required=required, widget=widget, *args, **kwargs)
--- /dev/null
+# -*- coding: utf-8 -*-
+from django.contrib.sites.models import Site
+from django.core.exceptions import ValidationError
+from django.core.files.uploadedfile import UploadedFile
+from django.core.mail import send_mail, mail_managers
+from django.core.urlresolvers import reverse
+from django.core.validators import validate_email
+from django import forms
+from django.template.loader import render_to_string
+from django.template import RequestContext
+from django.utils.translation import ugettext_lazy as _
+
+
+contact_forms = {}
+admin_list_width = 0
+
+
+class ContactFormMeta(forms.Form.__class__):
+ def __new__(cls, name, bases, attrs):
+ global admin_list_width
+ model = super(ContactFormMeta, cls).__new__(cls, name, bases, attrs)
+ assert model.form_tag not in contact_forms, 'Duplicate form_tag.'
+ if model.admin_list:
+ admin_list_width = max(admin_list_width, len(model.admin_list))
+ contact_forms[model.form_tag] = model
+ return model
+
+
+class ContactForm(forms.Form):
+ """Subclass and define some fields."""
+ __metaclass__ = ContactFormMeta
+
+ form_tag = None
+ form_title = _('Contact form')
+ submit_label = _('Submit')
+ admin_list = None
+ result_page = False
+
+ required_css_class = 'required'
+ # a subclass has to implement this field, but doing it here breaks the order
+ contact = NotImplemented
+
+ def save(self, request, formsets=None):
+ from .models import Attachment, Contact
+ body = {}
+ for name, value in self.cleaned_data.items():
+ if not isinstance(value, UploadedFile) and name != 'contact':
+ body[name] = value
+
+ for formset in formsets or []:
+ for f in formset.forms:
+ sub_body = {}
+ for name, value in f.cleaned_data.items():
+ if not isinstance(value, UploadedFile):
+ sub_body[name] = value
+ if sub_body:
+ body.setdefault(f.form_tag, []).append(sub_body)
+
+ contact = Contact.objects.create(
+ body=body,
+ ip=request.META['REMOTE_ADDR'],
+ contact=self.cleaned_data['contact'],
+ form_tag=self.form_tag)
+ for name, value in self.cleaned_data.items():
+ if isinstance(value, UploadedFile):
+ attachment = Attachment(contact=contact, tag=name)
+ attachment.file.save(value.name, value)
+ attachment.save()
+
+ site = Site.objects.get_current()
+ dictionary = {
+ 'form_tag': self.form_tag,
+ 'site_name': getattr(self, 'site_name', site.name),
+ 'site_domain': getattr(self, 'site_domain', site.domain),
+ 'contact': contact,
+ }
+ context = RequestContext(request)
+ mail_managers_subject = render_to_string([
+ 'contact/%s/mail_managers_subject.txt' % self.form_tag,
+ 'contact/mail_managers_subject.txt',
+ ], dictionary, context).strip()
+ mail_managers_body = render_to_string([
+ 'contact/%s/mail_managers_body.txt' % self.form_tag,
+ 'contact/mail_managers_body.txt',
+ ], dictionary, context)
+ mail_managers(mail_managers_subject, mail_managers_body, fail_silently=True)
+
+ try:
+ validate_email(contact.contact)
+ except ValidationError:
+ pass
+ else:
+ mail_subject = render_to_string([
+ 'contact/%s/mail_subject.txt' % self.form_tag,
+ 'contact/mail_subject.txt',
+ ], dictionary, context).strip()
+ if self.result_page:
+ mail_body = render_to_string(
+ 'contact/%s/results_email.txt' % contact.form_tag,
+ {
+ 'contact': contact,
+ 'results': self.results(contact),
+ }, context)
+ else:
+ mail_body = render_to_string([
+ 'contact/%s/mail_body.txt' % self.form_tag,
+ 'contact/mail_body.txt',
+ ], dictionary, context)
+ send_mail(mail_subject, mail_body, 'no-reply@%s' % site.domain, [contact.contact], fail_silently=True)
+
+ return contact
--- /dev/null
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2013-11-05 10:16+0100\n"
+"PO-Revision-Date: 2012-10-10 13:12+0100\n"
+"Last-Translator: Radek Czajka <radoslaw.czajka@nowoczesnapolska.org.pl>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
+"|| n%100>=20) ? 1 : 2)\n"
+
+#: admin.py:77
+msgid "Body"
+msgstr "Treść"
+
+#: admin.py:101
+msgid "all"
+msgstr "wszystko"
+
+#: admin.py:101
+msgid "contacts"
+msgstr "kontakty"
+
+#: forms.py:29
+msgid "Contact form"
+msgstr "Formularz kontaktowy"
+
+#: forms.py:30
+msgid "Submit"
+msgstr "Wyślij"
+
+#: models.py:11
+msgid "submission date"
+msgstr "data wysłania"
+
+#: models.py:12
+msgid "IP address"
+msgstr "adres IP"
+
+#: models.py:13
+msgid "contact"
+msgstr "kontakt"
+
+#: models.py:14
+msgid "form"
+msgstr "formularz"
+
+#: models.py:15
+msgid "body"
+msgstr "treść"
+
+#: models.py:29
+msgid "submitted form"
+msgstr "przysłany formularz"
+
+#: models.py:30
+msgid "submitted forms"
+msgstr "przysłane formularze"
+
+#: templates/admin/contact/contact/change_list.html:12
+msgid "Extract"
+msgstr "Ekstrakt"
+
+#: templates/contact/mail_body.txt:2 templates/contact/mail_subject.txt:1
+#, python-format
+msgid "Thank you for contacting us at %(site_name)s."
+msgstr "Dziękujemy za skontaktowanie się z nami na stronie %(site_name)s."
+
+#: templates/contact/mail_body.txt:3
+msgid "Your submission has been referred to the project coordinator."
+msgstr "Twoje zgłoszenie zostało przekazane osobie koordynującej projekt."
+
+#: templates/contact/mail_body.txt:6
+msgid "Message sent automatically. Please do not reply to it."
+msgstr "Wiadomość wysłana automatycznie, prosimy nie odpowiadać."
+
+#: templates/contact/thanks.html:4 templates/contact/thanks.html.py:8
+msgid "Thank you"
+msgstr "Dziękujemy"
+
+#: templates/contact/thanks.html:11
+msgid "Thank you for submitting the form."
+msgstr "Dziękujemy za wypełnienie formularza."
--- /dev/null
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+import jsonfield.fields
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='Attachment',
+ fields=[
+ ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+ ('tag', models.CharField(max_length=64)),
+ ('file', models.FileField(upload_to=b'contact/attachment')),
+ ],
+ ),
+ migrations.CreateModel(
+ name='Contact',
+ fields=[
+ ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+ ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='submission date')),
+ ('ip', models.GenericIPAddressField(verbose_name='IP address')),
+ ('contact', models.EmailField(max_length=128, verbose_name='contact')),
+ ('form_tag', models.CharField(max_length=32, verbose_name='form', db_index=True)),
+ ('body', jsonfield.fields.JSONField(verbose_name='body')),
+ ],
+ options={
+ 'ordering': ('-created_at',),
+ 'verbose_name': 'submitted form',
+ 'verbose_name_plural': 'submitted forms',
+ },
+ ),
+ migrations.AddField(
+ model_name='attachment',
+ name='contact',
+ field=models.ForeignKey(to='contact.Contact'),
+ ),
+ ]
--- /dev/null
+# -*- coding: utf-8 -*-
+import yaml
+from hashlib import sha1
+from django.db import models
+from django.utils.encoding import smart_unicode
+from django.utils.translation import ugettext_lazy as _
+from jsonfield import JSONField
+from . import app_settings
+
+
+class Contact(models.Model):
+ created_at = models.DateTimeField(_('submission date'), auto_now_add=True)
+ ip = models.GenericIPAddressField(_('IP address'))
+ contact = models.EmailField(_('contact'), max_length=128)
+ form_tag = models.CharField(_('form'), max_length=32, db_index=True)
+ body = JSONField(_('body'))
+
+ @staticmethod
+ def pretty_print(value, for_html=False):
+ if type(value) in (tuple, list, dict):
+ value = yaml.safe_dump(value, allow_unicode=True, default_flow_style=False)
+ if for_html:
+ value = smart_unicode(value).replace(u" ", unichr(160))
+ return value
+
+ class Meta:
+ ordering = ('-created_at',)
+ verbose_name = _('submitted form')
+ verbose_name_plural = _('submitted forms')
+
+ def __unicode__(self):
+ return unicode(self.created_at)
+
+ def digest(self):
+ serialized_body = ';'.join(sorted('%s:%s' % item for item in self.body.iteritems()))
+ data = '%s%s%s%s%s' % (self.id, self.contact, serialized_body, self.ip, self.form_tag)
+ return sha1(data).hexdigest()
+
+
+class Attachment(models.Model):
+ contact = models.ForeignKey(Contact)
+ tag = models.CharField(max_length=64)
+ file = models.FileField(upload_to='contact/attachment')
+
+ @models.permalink
+ def get_absolute_url(self):
+ return 'contact_attachment', [self.contact_id, self.tag]
+
+
+__import__(app_settings.FORMS_MODULE)
--- /dev/null
+{% extends "admin/change_list.html" %}
+{% load i18n %}
+{% load admin_urls %}
+
+
+{% block object-tools-items %}
+ {{block.super}}
+ {% if request.GET.form_tag %}
+ {% for extract_type in extract_types %}
+ <li>
+ <a href="{% url 'admin:contact_extract' form_tag=request.GET.form_tag extract_type_slug=extract_type.slug %}?created_at__month={{request.GET.created_at__month}}&created_at__year={{request.GET.created_at__year}}">
+ {% trans 'Extract' %}: {{extract_type.label}}
+ </a>
+ </li>
+ {% endfor %}
+ {% endif %}
+{% endblock %}
+
--- /dev/null
+{% extends "base/base.html" %}
+
+{% block title %}{{ title }}{% endblock %}
+
+{% block body %}
+
+ <h1>{{ title }}</h1>
+
+ {% block contact_form_description %}
+ <p class="notice">Rejestracja została zamknięta.</p>
+ {% endblock %}
+
+{% endblock %}
--- /dev/null
+{% extends form.base_template|default:"base/base.html" %}
+{% load chunks %}
+{% load honeypot %}
+
+{% block title %}{{ form.form_title }}{% endblock %}
+
+{% block body %}
+
+ <h1>{% block contact_form_title %}{{ form.form_title }}{% endblock %}</h1>
+
+ <div class="form-info">
+ {% block contact_form_description %}
+ {% chunk "contact_form__"|add:form.form_tag %}
+ {% endblock %}
+ </div>
+
+ <form method="POST" action="." enctype="multipart/form-data" class="submit-form">
+ {% csrf_token %}
+ {% render_honeypot_field %}
+ {% block form %}
+ <table>
+ {{ form.as_table }}
+ <tr><td></td><td><button>{% block contact_form_submit %}{{ form.submit_label }}{% endblock %}</button></td></tr>
+ </table>
+ {% endblock %}
+ </form>
+
+{% endblock %}
--- /dev/null
+{% load i18n %}
+{% blocktrans %}Thank you for contacting us at {{ site_name }}.{% endblocktrans %}
+{% trans "Your submission has been referred to the project coordinator." %}
+
+--
+{% trans "Message sent automatically. Please do not reply to it." %}
--- /dev/null
+{% load pretty_print from contact_tags %}{% load subdomainurls %}Wypełniono formularz {{ form_tag }} na stronie {{ site_name }}.
+
+{% url 'admin:contact_contact_change' None contact.pk %}
+
+{% for k, v in contact.body.items %}
+{{ k }}:
+{{ v|pretty_print }}
+{% endfor %}
+{% for attachment in contact.attachment_set.all %}
+{{ attachment.tag }}:
+http://{{ site_domain }}{{ attachment.get_absolute_url }}
+{% endfor %}
--- /dev/null
+Wypełniono formularz {{ form_tag }} na stronie {{ site_name }}.
\ No newline at end of file
--- /dev/null
+{% load i18n %}{% blocktrans %}Thank you for contacting us at {{ site_name }}.{% endblocktrans %}
\ No newline at end of file
--- /dev/null
+{% extends base_template|default:"base.html" %}
+{% load i18n %}
+
+{% block title %}{% trans "Thank you" %}{% endblock %}
+
+{% block body %}
+
+ <h1>{% block contact_form_title %}{% trans "Thank you" %}{% endblock %}</h1>
+
+ {% block contact_form_description %}
+ <p class="notice">{% trans "Thank you for submitting the form." %}</p>
+ {% endblock %}
+
+{% endblock %}
--- /dev/null
+# -*- coding: utf-8 -*-
+from django.template import Library
+from contact.models import Contact
+
+register = Library()
+
+
+@register.filter
+def pretty_print(value):
+ return Contact.pretty_print(value)
--- /dev/null
+# -*- coding: utf-8 -*-
+from django.conf.urls import patterns, url
+from . import views
+
+urlpatterns = patterns(
+ 'contact.views',
+ url(r'^(?P<form_tag>[^/]+)/$', views.form, name='contact_form'),
+ url(r'^(?P<form_tag>[^/]+)/thanks/$', views.thanks, name='contact_thanks'),
+ url(r'^attachment/(?P<contact_id>\d+)/(?P<tag>[^/]+)/$', views.attachment, name='contact_attachment'),
+ url(r'^results/(?P<contact_id>\d+)/(?P<digest>[0-9a-f]+)/', views.results, name='contact_results'),
+)
--- /dev/null
+# -*- coding: utf-8 -*-
+from urllib import unquote
+
+from django.contrib.auth.decorators import permission_required
+from django.http import Http404
+from django.shortcuts import get_object_or_404, redirect, render
+from fnpdjango.utils.views import serve_file
+from honeypot.decorators import check_honeypot
+
+from .forms import contact_forms
+from .models import Attachment, Contact
+
+
+@check_honeypot
+def form(request, form_tag, force_enabled=False):
+ try:
+ form_class = contact_forms[form_tag]
+ except KeyError:
+ raise Http404
+ if (getattr(form_class, 'disabled', False) and
+ not (force_enabled and request.user.is_superuser)):
+ template = getattr(form_class, 'disabled_template', None)
+ if template:
+ return render(request, template, {'title': form_class.form_title})
+ raise Http404
+ if request.method == 'POST':
+ form = form_class(request.POST, request.FILES)
+ else:
+ form = form_class(initial=request.GET)
+ formset_classes = getattr(form, 'form_formsets', {})
+ if request.method == 'POST':
+ formsets = {
+ prefix: formset_class(request.POST, request.FILES, prefix=prefix)
+ for prefix, formset_class in formset_classes.iteritems()}
+ if form.is_valid() and all(formset.is_valid() for formset in formsets.itervalues()):
+ contact = form.save(request, formsets.values())
+ if form.result_page:
+ return redirect('contact_results', contact.id, contact.digest())
+ else:
+ return redirect('contact_thanks', form_tag)
+ else:
+ formsets = {prefix: formset_class(prefix=prefix) for prefix, formset_class in formset_classes.iteritems()}
+
+ return render(
+ request, ['contact/%s/form.html' % form_tag, 'contact/form.html'],
+ {'form': form, 'formsets': formsets}
+ )
+
+
+def thanks(request, form_tag):
+ try:
+ form_class = contact_forms[form_tag]
+ except KeyError:
+ raise Http404
+
+ return render(
+ request, ['contact/%s/thanks.html' % form_tag, 'contact/thanks.html'],
+ {'base_template': getattr(form_class, 'base_template', None)})
+
+
+def results(request, contact_id, digest):
+ contact = get_object_or_404(Contact, id=contact_id)
+ if digest != contact.digest():
+ raise Http404
+ try:
+ form_class = contact_forms[contact.form_tag]
+ except KeyError:
+ raise Http404
+
+ return render(
+ request, 'contact/%s/results.html' % contact.form_tag,
+ {
+ 'results': form_class.results(contact),
+ 'base_template': getattr(form_class, 'base_template', None),
+ }
+ )
+
+
+@permission_required('contact.change_attachment')
+def attachment(request, contact_id, tag):
+ attachment = get_object_or_404(Attachment, contact_id=contact_id, tag=tag)
+ attachment_url = unquote(attachment.file.url)
+ return serve_file(attachment_url)
--- /dev/null
+# -*- coding: utf-8 -*-
+# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
+from django import forms
+from django.forms.util import flatatt
+from django.utils.html import format_html
+
+
+class HeaderWidget(forms.widgets.Widget):
+ def render(self, name, value, attrs=None):
+ attrs.update(self.attrs)
+ return format_html('<a{0}></a>', flatatt(attrs))
--- /dev/null
+# -*- coding: utf-8 -*-
+# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
+from django.utils.functional import lazy
+from django.utils.safestring import mark_safe
+
+from contact.forms import ContactForm
+from contact.fields import HeaderField
+from django import forms
+
+mark_safe_lazy = lazy(mark_safe, unicode)
+
+
+class KonkursForm(ContactForm):
+ form_tag = 'konkurs'
+ form_title = u"Konkurs Trzy strony"
+ admin_list = ['podpis', 'contact', 'temat']
+
+ opiekun_header = HeaderField(label=u'Dane\xa0Opiekuna/Opiekunki')
+ opiekun_nazwisko = forms.CharField(label=u'Imię i nazwisko', max_length=128)
+ contact = forms.EmailField(label=u'Adres e-mail', max_length=128)
+ opiekun_tel = forms.CharField(label=u'Numer telefonu', max_length=32)
+ nazwa_dkk = forms.CharField(label=u'Nazwa DKK', max_length=128)
+ adres_dkk = forms.CharField(label=u'Adres DKK', max_length=128)
+
+ uczestnik_header = HeaderField(label=u'Dane\xa0Uczestnika/Uczestniczki')
+ uczestnik_imie = forms.CharField(label=u'Imię', max_length=128)
+ uczestnik_nazwisko = forms.CharField(label=u'Nazwisko', max_length=128)
+ uczestnik_email = forms.EmailField(label=u'Adres e-mail', max_length=128)
+ wiek = forms.ChoiceField(label=u'Kategoria wiekowa', choices=(
+ ('0-11', 'do 11 lat'),
+ ('12-15', '12–15 lat'),
+ ('16-19', '16–19 lat'),
+ ))
+ tytul = forms.CharField(label=u'Tytuł opowiadania', max_length=255)
+ plik = forms.FileField(
+ label=u'Plik z opowiadaniem',
+ help_text=u'Prosimy o nazwanie pliku imieniem i nazwiskiem autora.')
+
+ agree_header = HeaderField(label=u'Oświadczenia')
+ agree_terms = forms.BooleanField(
+ label='Regulamin',
+ help_text=mark_safe_lazy(
+ u'Znam i akceptuję <a href="/media/chunks/attachment/Regulamin_konkursu_Trzy_strony.pdf">'
+ u'Regulamin Konkursu</a>.'),
+ )
+ agree_data = forms.BooleanField(
+ label='Przetwarzanie danych osobowych',
+ help_text=u'Oświadczam, że wyrażam zgodę na przetwarzanie danych osobowych zawartych w niniejszym formularzu '
+ u'zgłoszeniowym przez Fundację Nowoczesna Polska (administratora danych) z siedzibą w Warszawie (00-514) '
+ u'przy ul. Marszałkowskiej 84/92 lok. 125 na potrzeby organizacji Konkursu. Jednocześnie oświadczam, '
+ u'że zostałam/em poinformowana/y o tym, że mam prawo wglądu w treść swoich danych i możliwość ich '
+ u'poprawiania oraz że ich podanie jest dobrowolne, ale niezbędne do dokonania zgłoszenia.')
+ agree_license = forms.BooleanField(
+ label='Licencja',
+ help_text=mark_safe_lazy(
+ u'Wyrażam zgodę oraz potwierdzam, że autor/ka (lub ich przedstawiciele ustawowi – gdy dotyczy) '
+ u'wyrazili zgodę na korzystanie z opowiadania zgodnie z postanowieniami wolnej licencji '
+ u'<a href="https://creativecommons.org/licenses/by-sa/3.0/pl/">Creative Commons Uznanie autorstwa – '
+ u'Na tych samych warunkach 3.0</a>. Licencja pozwala każdemu na swobodne, nieodpłatne korzystanie z utworu '
+ u'w oryginale oraz w postaci opracowań do wszelkich celów wymagając poszanowania autorstwa i innych praw '
+ u'osobistych oraz tego, aby ewentualne opracowania utworu były także udostępniane na tej samej licencji.'))
+ agree_wizerunek = forms.BooleanField(
+ label='Rozpowszechnianie wizerunku',
+ help_text=u'Wyrażam zgodę oraz potwierdzam, że autor/ka opowiadania (lub ich przedstawiciele ustawowi – '
+ u'gdy dotyczy) wyrazili zgodę na fotografowanie i nagrywanie podczas gali wręczenia nagród i następnie '
+ u'rozpowszechnianie ich wizerunków.')
'polls',
'libraries',
'newsletter',
+ 'contact',
]
GETPAID_BACKENDS = (
CATALOGUE_MIN_INITIALS = 60
PICTURE_PAGE_SIZE = 20
+
+CONTACT_FORMS_MODULE = 'wolnelektury.contact_forms'
padding-bottom: 1em;
}
- .required th:after {
- content: " *";
+ .required th:before {
+ content: "* ";
}
.errorlist {
<ul>
<li><a href="https://nowoczesnapolska.org.pl/prywatnosc/">{% trans "Privacy policy" %}</a></li>
{% infopages_on_main %}
+ <li><a href="{% url 'contact_form' 'konkurs' %}">{% trans "Konkurs Trzy strony" %}</a></li>
</ul>
<div class="social-links">
url(r'^chunks/', include('chunks.urls')),
url(r'^sponsors/', include('sponsors.urls')),
url(r'^newsletter/', include('newsletter.urls')),
+ url(r'^formularz/', include('contact.urls')),
# Admin panel
url(r'^admin/catalogue/book/import$', catalogue.views.import_book, name='import_book'),
# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
#
+import codecs
+import csv
+import cStringIO
import json
import os
from functools import wraps
u'[WolneLektury] ' + subject,
message + u"\n\n-- \n" + ugettext(u'Message sent automatically. Please do not reply.'),
'no-reply@wolnelektury.pl', recipient_list, **kwargs)
+
+
+# source: https://docs.python.org/2/library/csv.html#examples
+class UnicodeCSVWriter(object):
+ """
+ A CSV writer which will write rows to CSV file "f",
+ which is encoded in the given encoding.
+ """
+
+ def __init__(self, f, dialect=csv.excel, encoding="utf-8", **kwds):
+ # Redirect output to a queue
+ self.queue = cStringIO.StringIO()
+ self.writer = csv.writer(self.queue, dialect=dialect, **kwds)
+ self.stream = f
+ self.encoder = codecs.getincrementalencoder(encoding)()
+
+ def writerow(self, row):
+ self.writer.writerow([s.encode("utf-8") for s in row])
+ # Fetch UTF-8 output from the queue ...
+ data = self.queue.getvalue()
+ data = data.decode("utf-8")
+ # ... and reencode it into the target encoding
+ data = self.encoder.encode(data)
+ # write to the target stream
+ self.stream.write(data)
+ # empty queue
+ self.queue.truncate(0)
+
+ def writerows(self, rows):
+ for row in rows:
+ self.writerow(row)