-# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
-# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
-#
-"""
-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
-# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
-# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
-#
-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 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.get_body_json().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)
- body = instance.get_body_json()
- assert isinstance(body, dict)
- except (Contact.DoesNotExist, AssertionError):
- pass
- else:
- # Create readonly fields from the body JSON.
- attachments = list(instance.attachment_set.all())
- body_keys = list(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 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):
- return [
- 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.get_body_json().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.get_body_json())]
- 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], str):
- pass
- elif isinstance(record[key], bool):
- record[key] = 'tak' if record[key] else 'nie'
- elif isinstance(record[key], (list, tuple)) and all(isinstance(v, str) 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
-# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
-# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
-#
-import json
-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.validators import validate_email
-from django import forms
-from django.template.loader import render_to_string
-from django.template import RequestContext
-from django.urls import reverse
-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, metaclass=ContactFormMeta):
- """Subclass and define some fields."""
-
- 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=json.dumps(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,
- }
- mail_managers_subject = render_to_string([
- 'contact/%s/mail_managers_subject.txt' % self.form_tag,
- 'contact/mail_managers_subject.txt',
- ], dictionary, request).strip()
- mail_managers_body = render_to_string([
- 'contact/%s/mail_managers_body.txt' % self.form_tag,
- 'contact/mail_managers_body.txt',
- ], dictionary, request)
- 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, request).strip()
- if self.result_page:
- mail_body = render_to_string(
- 'contact/%s/results_email.txt' % contact.form_tag,
- {
- 'contact': contact,
- 'results': self.results(contact),
- }, request)
- else:
- mail_body = render_to_string([
- 'contact/%s/mail_body.txt' % self.form_tag,
- 'contact/mail_body.txt',
- ], dictionary, request)
- 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
+# Generated by Django 2.2.5 on 2019-09-19 12:12
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('contact', '0001_initial'),
+ ]
+
+ operations = [
+ migrations.DeleteModel(
+ name='Attachment',
+ ),
+ migrations.DeleteModel(
+ name='Contact',
+ ),
+ ]
+++ /dev/null
-# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
-# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
-#
-import json
-import yaml
-from hashlib import sha1
-from django.db import models
-from django.urls import reverse
-from django.utils.encoding import smart_text
-from django.utils.translation import ugettext_lazy as _
-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 = models.TextField(_('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_text(value).replace(" ", chr(160))
- return value
-
- class Meta:
- ordering = ('-created_at',)
- verbose_name = _('submitted form')
- verbose_name_plural = _('submitted forms')
-
- def __str__(self):
- return str(self.created_at)
-
- def digest(self):
- serialized_body = ';'.join(sorted('%s:%s' % item for item in self.get_body_json().items()))
- data = '%s%s%s%s%s' % (self.id, self.contact, serialized_body, self.ip, self.form_tag)
- return sha1(data).hexdigest()
-
- def keys(self):
- try:
- from .views import contact_forms
- orig_fields = contact_forms[self.form_tag]().fields
- except KeyError:
- orig_fields = {}
- return list(orig_fields.keys())
-
- def items(self):
- body = self.get_body_json()
- return [(key, body[key]) for key in self.keys() if key in body]
-
- def get_body_json(self):
- return json.loads(self.body or '{}')
-
-
-class Attachment(models.Model):
- contact = models.ForeignKey(Contact, models.CASCADE)
- tag = models.CharField(max_length=64)
- file = models.FileField(upload_to='contact/attachment')
-
- def get_absolute_url(self):
- return reverse('contact_attachment', args=[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 %}Wypełniono formularz {{ form_tag }} na stronie {{ site_name }}.
-
-https://{{site_domain}}{% url 'admin:contact_contact_change' contact.pk %}
-
-{% for k, v in contact.items %}
-{{ k }}:
-{{ v|pretty_print }}
-{% endfor %}
-{% for attachment in contact.attachment_set.all %}
-{{ attachment.tag }}:
-https://{{ 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
-# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
-# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
-#
-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
-# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
-# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
-#
-from django.conf.urls import url
-from . import views
-
-
-urlpatterns = [
- 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
-# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
-# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
-#
-from urllib.parse import unquote
-
-from datetime import datetime
-from django.contrib.auth.decorators import permission_required
-from django.http import Http404
-from django.shortcuts import get_object_or_404, redirect, render
-from django.utils import timezone
-from django.views.decorators.cache import never_cache
-from fnpdjango.utils.views import serve_file
-from honeypot.decorators import check_honeypot
-
-from wolnelektury.utils import localtime_to_utc
-from .forms import contact_forms
-from .models import Attachment, Contact
-
-
-@check_honeypot
-@never_cache
-def form(request, form_tag, force_enabled=False):
- try:
- form_class = contact_forms[form_tag]
- except KeyError:
- raise Http404
- if not (force_enabled and request.user.is_superuser):
- disabled = getattr(form_class, 'disabled', False)
- end_tuple = getattr(form_class, 'ends_on', None)
- end_time = localtime_to_utc(datetime(*end_tuple)) if end_tuple else None
- expired = end_time and end_time < timezone.now()
- if disabled or expired:
- 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.items()}
- if form.is_valid() and all(formset.is_valid() for formset in formsets.values()):
- 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.items()}
-
- 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)
PICTURE_PAGE_SIZE = 20
-CONTACT_FORMS_MODULE = 'wolnelektury.contact_forms'
-
PAYU_POS = {
'300746': {
'client_secret': '2ee86a66e5d97e3fadc400c9f19b065d',
+++ /dev/null
-{% extends "contact/form.html" %}
-
-{% block body %}
- {{ block.super }}
- <p><a href="{{ MEDIA_URL }}chunks/attachment/Zgoda_dla_rodzic%C3%B3w.doc">Formularz zgody dla rodziców i opiekunów</a></p>
-{% endblock %}
\ No newline at end of file