Contact forms.
authorRadek Czajka <radoslaw.czajka@nowoczesnapolska.org.pl>
Wed, 20 Feb 2013 10:49:53 +0000 (11:49 +0100)
committerRadek Czajka <radoslaw.czajka@nowoczesnapolska.org.pl>
Wed, 20 Feb 2013 11:20:58 +0000 (12:20 +0100)
36 files changed:
catalogue/templates/catalogue/lesson/appendix/lesson_detail.html
catalogue/templates/catalogue/lesson/lesson_detail.html
chunks/templatetags/chunks.py
contact/__init__.py [new file with mode: 0644]
contact/admin.py [new file with mode: 0644]
contact/forms.py [new file with mode: 0644]
contact/locale/pl/LC_MESSAGES/django.mo [new file with mode: 0644]
contact/locale/pl/LC_MESSAGES/django.po [new file with mode: 0644]
contact/migrations/0001_initial.py [new file with mode: 0644]
contact/migrations/0002_auto__add_attachment.py [new file with mode: 0644]
contact/migrations/__init__.py [new file with mode: 0644]
contact/models.py [new file with mode: 0644]
contact/templates/contact/form.html [new file with mode: 0644]
contact/templates/contact/mail_body.txt [new file with mode: 0644]
contact/templates/contact/mail_managers_body.txt [new file with mode: 0644]
contact/templates/contact/mail_managers_subject.txt [new file with mode: 0644]
contact/templates/contact/mail_subject.txt [new file with mode: 0644]
contact/templates/contact/thanks.html [new file with mode: 0644]
contact/urls.py [new file with mode: 0644]
contact/views.py [new file with mode: 0644]
edumed/contact_forms.py [new file with mode: 0644]
edumed/settings.d/30-apps.py
edumed/settings.d/40-middleware.py
edumed/settings.d/50-contrib.py
edumed/settings.d/50-static.py
edumed/settings.d/60-custom.py
edumed/static/css/form.css [new file with mode: 0644]
edumed/static/css/form.scss [new file with mode: 0755]
edumed/templates/contact/konkurs/mail_body.txt [new file with mode: 0644]
edumed/templates/contact/konkurs/mail_subject.txt [new file with mode: 0644]
edumed/templates/contact/konkurs/thanks.html [new file with mode: 0644]
edumed/templates/contact/sugestie/mail_body.txt [new file with mode: 0644]
edumed/templates/contact/sugestie/mail_subject.txt [new file with mode: 0644]
edumed/templates/contact/sugestie/thanks.html [new file with mode: 0644]
edumed/urls.py
requirements.txt

index b4bbc94..fae3bcb 100755 (executable)
@@ -17,3 +17,9 @@
 </section>
 
 {% endblock %}
 </section>
 
 {% endblock %}
+
+{% block suggest-link %}
+<a href="{% url 'contact_form' 'sugestie' %}?temat={{ object.title|urlencode }}">
+    Zgłoś swoją uwagę na temat tej strony.
+</a>
+{% endblock %}
index 8eec0da..dfd844e 100755 (executable)
 {% endif %}
 
 <div class="clr"></div>
 {% endif %}
 
 <div class="clr"></div>
+
+<p class="section-info">
+    {% block suggest-link %}
+    <a href="{% url 'contact_form' 'sugestie' %}?temat={{ 'Lekcja: '|add:object.title|urlencode }}">
+        Zgłoś swoją uwagę na temat tej lekcji.
+    </a>
+    {% endblock %}
+</p>
+
 </footer>
 </div>
 
 </footer>
 </div>
 
index 083c48a..fd24b02 100644 (file)
@@ -1,53 +1,29 @@
 from django import template
 from django.db import models
 from django.core.cache import cache
 from django import template
 from django.db import models
 from django.core.cache import cache
+from ..models import Chunk, Attachment
 
 
 register = template.Library()
 
 
 
 register = template.Library()
 
-Chunk = models.get_model('chunks', 'chunk')
-Attachment = models.get_model('chunks', 'attachment')
-
-
-def do_get_chunk(parser, token):
-    # split_contents() knows not to split quoted strings.
-    tokens = token.split_contents()
-    if len(tokens) < 2 or len(tokens) > 3:
-        raise template.TemplateSyntaxError, "%r tag should have either 2 or 3 arguments" % (tokens[0],)
-    if len(tokens) == 2:
-        tag_name, key = tokens
-        cache_time = 0
-    if len(tokens) == 3:
-        tag_name, key, cache_time = tokens
-    # Check to see if the key is properly double/single quoted
-    if not (key[0] == key[-1] and key[0] in ('"', "'")):
-        raise template.TemplateSyntaxError, "%r tag's argument should be in quotes" % tag_name
-    # Send key without quotes and caching time
-    return ChunkNode(key[1:-1], cache_time)
-
-
-class ChunkNode(template.Node):
-    def __init__(self, key, cache_time=0):
-       self.key = key
-       self.cache_time = cache_time
-
-    def render(self, context):
-        try:
-            cache_key = 'chunk_' + self.key
-            c = cache.get(cache_key)
-            if c is None:
-                c = Chunk.objects.get(key=self.key)
-                cache.set(cache_key, c, int(self.cache_time))
-            content = c.content
-        except Chunk.DoesNotExist:
-            n = Chunk(key=self.key)
-            n.save()
-            return ''
-        return content
-
-register.tag('chunk', do_get_chunk)
+
+@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
 def attachment(key, cache_time=0):
     try:
         cache_key = 'attachment_' + key
@@ -59,5 +35,4 @@ def attachment(key, cache_time=0):
     except Attachment.DoesNotExist:
         return ''
 
     except Attachment.DoesNotExist:
         return ''
 
-register.simple_tag(attachment)
 
 
diff --git a/contact/__init__.py b/contact/__init__.py
new file mode 100644 (file)
index 0000000..0f043ed
--- /dev/null
@@ -0,0 +1,52 @@
+"""
+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')
diff --git a/contact/admin.py b/contact/admin.py
new file mode 100644 (file)
index 0000000..3776fc4
--- /dev/null
@@ -0,0 +1,94 @@
+from django.contrib import admin
+from django.forms import ModelForm
+from .models import Contact
+from django.utils.translation import ugettext as _
+from .forms import contact_forms, admin_list_width
+from django.template import Template
+from django.utils.safestring import mark_safe
+
+
+class ContactAdminMeta(admin.ModelAdmin.__metaclass__):
+    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']
+
+    def admin_list(self, obj, nr):
+        try:
+            field_name = contact_forms[obj.form_tag].admin_list[nr]
+        except BaseException, e:
+            return ''
+        else:
+            return obj.body.get(field_name, '')
+
+    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, 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.
+                body_fields = ['body__%s' % k for k in instance.body.keys()]
+                attachments = list(instance.attachment_set.all())
+                body_fields += ['body__%s' % a.tag for a in attachments]
+                self.readonly_fields.extend(body_fields)
+
+                # Find the original form.
+                try:
+                    orig_fields = contact_forms[instance.form_tag]().fields
+                except KeyError:
+                    orig_fields = {}
+
+                # Try to preserve the original order.
+                admin_fields = []
+                orig_keys = list(orig_fields.keys())
+                while orig_keys:
+                    key = orig_keys.pop(0)
+                    key = "body__%s" % key
+                    if key in body_fields:
+                        admin_fields.append(key)
+                        body_fields.remove(key)
+                admin_fields.extend(body_fields)
+
+                self.fieldsets = [
+                    (None, {'fields': self.fields}),
+                    (_('Body'), {'fields': admin_fields}),
+                ]
+
+                # Create field getters for fields and attachments.
+                for k, v in instance.body.items():
+                    f = (lambda v: lambda self: v)(v)
+                    f.short_description = orig_fields[k].label if k in orig_fields else _(k)
+                    setattr(self, "body__%s" % k, f)
+
+                download_link = "<a href='%(url)s'>%(url)s</a>"
+                for attachment in attachments:
+                    k = attachment.tag
+                    link = mark_safe(download_link % {
+                            'url': attachment.get_absolute_url()})
+                    f = (lambda v: lambda self: v)(link)
+                    f.short_description = orig_fields[k].label if k in orig_fields else _(k)
+                    setattr(self, "body__%s" % k, f)
+        return super(ContactAdmin, self).change_view(request, object_id,
+            extra_context=extra_context)
+
+
+admin.site.register(Contact, ContactAdmin)
diff --git a/contact/forms.py b/contact/forms.py
new file mode 100644 (file)
index 0000000..8e78eed
--- /dev/null
@@ -0,0 +1,85 @@
+from django.contrib.sites.models import Site
+from django.core.files.uploadedfile import UploadedFile
+from django.core.mail import send_mail, mail_managers
+from django.core.validators import email_re
+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.__metaclass__):
+    def __new__(cls, *args, **kwargs):
+        global admin_list_width
+        model = super(ContactFormMeta, cls).__new__(cls, *args, **kwargs)
+        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
+
+    required_css_class = 'required'
+    contact = forms.CharField(max_length=128)
+
+    def save(self, request):
+        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
+        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': site.name,
+            '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)
+
+        if email_re.match(contact.contact):
+            mail_subject = render_to_string([
+                    'contact/%s/mail_subject.txt' % self.form_tag,
+                    'contact/mail_subject.txt', 
+                ], dictionary, context).strip()
+            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
diff --git a/contact/locale/pl/LC_MESSAGES/django.mo b/contact/locale/pl/LC_MESSAGES/django.mo
new file mode 100644 (file)
index 0000000..985b0c0
Binary files /dev/null and b/contact/locale/pl/LC_MESSAGES/django.mo differ
diff --git a/contact/locale/pl/LC_MESSAGES/django.po b/contact/locale/pl/LC_MESSAGES/django.po
new file mode 100644 (file)
index 0000000..7805958
--- /dev/null
@@ -0,0 +1,81 @@
+# 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: 2012-10-10 13:12+0200\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:49
+msgid "Body"
+msgstr "Treść"
+
+#: models.py:10
+msgid "submission date"
+msgstr "data wysłania"
+
+#: models.py:11
+msgid "IP address"
+msgstr "adres IP"
+
+#: models.py:12
+msgid "contact"
+msgstr "kontakt"
+
+#: models.py:13
+msgid "form"
+msgstr "formularz"
+
+#: models.py:14
+msgid "body"
+msgstr "treść"
+
+#: models.py:18
+msgid "submitted form"
+msgstr "przysłany formularz"
+
+#: models.py:19
+msgid "submitted forms"
+msgstr "przysłane formularze"
+
+#: templates/contact/form.html:5
+msgid "Contact form"
+msgstr "Formularz kontaktowy"
+
+#: templates/contact/form.html:14
+msgid "Submit"
+msgstr "Wyślij"
+
+#: 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:5
+msgid "Thank you"
+msgstr "Dziękujemy"
+
+#: templates/contact/thanks.html:8
+msgid "Thank you for submitting the contact form."
+msgstr "Dziękujemy za wypełnienie formularza kontaktowego."
+
diff --git a/contact/migrations/0001_initial.py b/contact/migrations/0001_initial.py
new file mode 100644 (file)
index 0000000..d16bf4c
--- /dev/null
@@ -0,0 +1,40 @@
+# -*- coding: utf-8 -*-
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+
+class Migration(SchemaMigration):
+
+    def forwards(self, orm):
+        # Adding model 'Contact'
+        db.create_table('contact_contact', (
+            ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+            ('created_at', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)),
+            ('ip', self.gf('django.db.models.fields.IPAddressField')(max_length=15)),
+            ('contact', self.gf('django.db.models.fields.CharField')(max_length=128)),
+            ('form_tag', self.gf('django.db.models.fields.CharField')(max_length=32)),
+            ('body', self.gf('jsonfield.fields.JSONField')()),
+        ))
+        db.send_create_signal('contact', ['Contact'])
+
+
+    def backwards(self, orm):
+        # Deleting model 'Contact'
+        db.delete_table('contact_contact')
+
+
+    models = {
+        'contact.contact': {
+            'Meta': {'ordering': "('-created_at',)", 'object_name': 'Contact'},
+            'body': ('jsonfield.fields.JSONField', [], {}),
+            'contact': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+            'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'form_tag': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'ip': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'})
+        }
+    }
+
+    complete_apps = ['contact']
\ No newline at end of file
diff --git a/contact/migrations/0002_auto__add_attachment.py b/contact/migrations/0002_auto__add_attachment.py
new file mode 100644 (file)
index 0000000..8dc031d
--- /dev/null
@@ -0,0 +1,51 @@
+# -*- coding: utf-8 -*-
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+
+class Migration(SchemaMigration):
+
+    def forwards(self, orm):
+        # Adding model 'Attachment'
+        db.create_table('contact_attachment', (
+            ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+            ('contact', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['contact.Contact'])),
+            ('tag', self.gf('django.db.models.fields.CharField')(max_length=64)),
+            ('file', self.gf('django.db.models.fields.files.FileField')(max_length=100)),
+        ))
+        db.send_create_signal('contact', ['Attachment'])
+
+        # Adding index on 'Contact', fields ['form_tag']
+        db.create_index('contact_contact', ['form_tag'])
+
+
+    def backwards(self, orm):
+        # Removing index on 'Contact', fields ['form_tag']
+        db.delete_index('contact_contact', ['form_tag'])
+
+        # Deleting model 'Attachment'
+        db.delete_table('contact_attachment')
+
+
+    models = {
+        'contact.attachment': {
+            'Meta': {'object_name': 'Attachment'},
+            'contact': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contact.Contact']"}),
+            'file': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'tag': ('django.db.models.fields.CharField', [], {'max_length': '64'})
+        },
+        'contact.contact': {
+            'Meta': {'ordering': "('-created_at',)", 'object_name': 'Contact'},
+            'body': ('jsonfield.fields.JSONField', [], {}),
+            'contact': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+            'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'form_tag': ('django.db.models.fields.CharField', [], {'max_length': '32', 'db_index': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'ip': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'})
+        }
+    }
+
+    complete_apps = ['contact']
\ No newline at end of file
diff --git a/contact/migrations/__init__.py b/contact/migrations/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/contact/models.py b/contact/models.py
new file mode 100644 (file)
index 0000000..21d8405
--- /dev/null
@@ -0,0 +1,35 @@
+# -*- coding: utf-8 -*-
+from django.core.files.storage import FileSystemStorage
+from django.db import models
+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.IPAddressField(_('IP address'))
+    contact = models.CharField(_('contact'), max_length=128)
+    form_tag = models.CharField(_('form'), max_length=32, db_index=True)
+    body = JSONField(_('body'))
+
+    class Meta:
+        ordering = ('-created_at',)
+        verbose_name = _('submitted form')
+        verbose_name_plural = _('submitted forms')
+
+    def __unicode__(self):
+        return unicode(self.created_at)
+
+
+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)
diff --git a/contact/templates/contact/form.html b/contact/templates/contact/form.html
new file mode 100644 (file)
index 0000000..963742e
--- /dev/null
@@ -0,0 +1,24 @@
+{% extends "base.html" %}
+{% load chunks %}
+
+{% 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 %}
+    <table>
+        {{ form.as_table }}
+        <tr><td></td><td><button>{% block contact_form_submit %}{{ form.submit_label }}{% endblock %}</button></td></tr>
+    </table>
+    </form>
+
+{% endblock %}
diff --git a/contact/templates/contact/mail_body.txt b/contact/templates/contact/mail_body.txt
new file mode 100644 (file)
index 0000000..5015757
--- /dev/null
@@ -0,0 +1,6 @@
+{% 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." %}
diff --git a/contact/templates/contact/mail_managers_body.txt b/contact/templates/contact/mail_managers_body.txt
new file mode 100644 (file)
index 0000000..386c9cd
--- /dev/null
@@ -0,0 +1,12 @@
+{% load url from future %}Wypełniono formularz {{ form_tag }} na stronie {{ site_name }}.
+
+http://{{ site_domain }}{% url 'admin:contact_contact_change' contact.pk %}
+
+{% for k, v in contact.body.items %}
+{{ k }}:
+{{ v }}
+{% endfor %}
+{% for attachment in contact.attachment_set.all %}
+{{ attachment.tag }}:
+http://{{ site_domain }}{{ attachment.get_absolute_url }}
+{% endfor %}
diff --git a/contact/templates/contact/mail_managers_subject.txt b/contact/templates/contact/mail_managers_subject.txt
new file mode 100644 (file)
index 0000000..12d2c8e
--- /dev/null
@@ -0,0 +1 @@
+Wypełniono formularz {{ form_tag }} na stronie {{ site_name }}.
\ No newline at end of file
diff --git a/contact/templates/contact/mail_subject.txt b/contact/templates/contact/mail_subject.txt
new file mode 100644 (file)
index 0000000..b8f586e
--- /dev/null
@@ -0,0 +1 @@
+{% load i18n %}{% blocktrans %}Thank you for contacting us at {{ site_name }}.{% endblocktrans %}
\ No newline at end of file
diff --git a/contact/templates/contact/thanks.html b/contact/templates/contact/thanks.html
new file mode 100644 (file)
index 0000000..cc061ed
--- /dev/null
@@ -0,0 +1,14 @@
+{% extends "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 contact form." %}</p>
+    {% endblock %}
+
+{% endblock %}
diff --git a/contact/urls.py b/contact/urls.py
new file mode 100644 (file)
index 0000000..de72e82
--- /dev/null
@@ -0,0 +1,9 @@
+from django.conf.urls.defaults import *
+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'),
+)
diff --git a/contact/views.py b/contact/views.py
new file mode 100644 (file)
index 0000000..d18598c
--- /dev/null
@@ -0,0 +1,40 @@
+from django.contrib.auth.decorators import permission_required
+from django.http import Http404, HttpResponse
+from django.shortcuts import get_object_or_404, redirect, render
+from django.utils.translation import ugettext_lazy as _
+from fnpdjango.utils.views import serve_file
+from .forms import contact_forms
+from .models import Attachment
+
+
+def form(request, form_tag):
+    try:
+        form_class = contact_forms[form_tag]
+    except KeyError:
+        raise Http404
+    if request.method == 'POST':
+        form = form_class(request.POST, request.FILES)
+        if form.is_valid():
+            form.save(request)
+            return redirect('contact_thanks', form_tag)
+    else:
+        form = form_class(initial=request.GET)
+    return render(request,
+                ['contact/%s/form.html' % form_tag, 'contact/form.html'],
+                {'form': form}
+            )
+
+
+def thanks(request, form_tag):
+    if form_tag not in contact_forms:
+        raise Http404
+
+    return render(request,
+                ['contact/%s/thanks.html' % form_tag, 'contact/thanks.html']
+            )
+
+
+@permission_required('contact.change_attachment')
+def attachment(request, contact_id, tag):
+    attachment = get_object_or_404(Attachment, contact_id=contact_id, tag=tag)
+    return serve_file(attachment.file.url)
diff --git a/edumed/contact_forms.py b/edumed/contact_forms.py
new file mode 100644 (file)
index 0000000..7286509
--- /dev/null
@@ -0,0 +1,48 @@
+# -*- coding: utf-8 -*-
+from django import forms
+from contact.forms import ContactForm
+
+
+class RegistrationForm(ContactForm):
+    form_tag = 'sugestie'
+    form_title = u"Zgłoś sugestię"
+    admin_list = ['podpis', 'contact', 'temat']
+
+    contact = forms.EmailField(label=u'E-mail', max_length=128, required=False)
+    podpis = forms.CharField(label=u'Podpis', max_length=128, required=False)
+    temat = forms.CharField(label=u'Temat zgłoszenia', max_length=255)
+    tresc = forms.CharField(label=u'Treść', widget=forms.Textarea, max_length=1800)
+
+
+class ContestForm(ContactForm):
+    form_tag = 'konkurs'
+    form_title = u"Zgłoś się do konkursu"
+    admin_list = ['name', 'organization', 'title']
+
+    nazwisko = forms.CharField(label=u'Imię i nazwisko', max_length=128)
+    contact = forms.EmailField(label=u'Adres e-mail', max_length=128)
+    instytucja = forms.CharField(label=u'Instytucja (nazwa, adres)', 
+            widget=forms.Textarea, max_length=1000)
+    tytul = forms.CharField(label=u'Tytuł przeprowadzonej lekcji',
+            help_text=u'proszę wymienić wszystkie, jeśli zostały przeprowadzone więcej niż jedne zajęcia', 
+            widget=forms.Textarea, max_length=1000)
+    uczestnicy = forms.CharField(label=u'Liczba uczestników', max_length=64)
+    trudnosci = forms.CharField(label=u'Czy w trakcie zajęć pojawiły się jakieś trudności? Jeśli tak, to jakie?', 
+            widget=forms.Textarea, max_length=2000)
+    pomocne = forms.CharField(label=u'Co w materiałach okazało się najbardziej pomocne w przygotowaniu i prowadzeniu lekcji?', 
+            widget=forms.Textarea, max_length=2000)
+    nieprzydatne = forms.CharField(label=u'Co w materiałach okazało się nieprzydatne w przygotowaniu i prowadzeniu lekcji?', 
+            widget=forms.Textarea, max_length=2000)
+    poprawic = forms.CharField(label=u'Jak możemy poprawić serwis edukacjamedialna.edu.pl?', 
+            widget=forms.Textarea, max_length=2000)
+    inne = forms.CharField(label=u'Inne uwagi i komentarze', 
+            widget=forms.Textarea, max_length=2000,
+            required=False)
+    zgoda_regulamin = forms.BooleanField(
+        label=u'Znam i akceptuję regulamin konkursu Medialog.',
+        help_text=u'Zobacz <a href="/media/chunks/attachment/Regulamin_konkursu_MediaLog_1.pdf">regulamin konkursu MediaLog</a>.'
+    )
+    zgoda_informacje = forms.BooleanField(
+        label=u'Wyrażam zgodę na otrzymywanie informacji od Fundacji Nowoczesna Polska związanych z edukacją medialną.',
+        required=False
+    )
index 0ba0726..e98a3ee 100644 (file)
@@ -9,11 +9,12 @@ INSTALLED_APPS = (
     # Disable, if not using Piwik.
     'piwik.django',
     # Disable, if not using CAS.
     # Disable, if not using Piwik.
     'piwik.django',
     # Disable, if not using CAS.
+    'honeypot',
     'django_cas',
     'sponsors',
     'haystack',
     'chunks',
     'django_cas',
     'sponsors',
     'haystack',
     'chunks',
-
+    'contact',
 
     'django.contrib.auth',
     'django.contrib.contenttypes',
 
     'django.contrib.auth',
     'django.contrib.contenttypes',
index b211d42..5700161 100644 (file)
@@ -6,6 +6,7 @@ MIDDLEWARE_CLASSES = tuple(x for x in (
 
     'django.middleware.common.CommonMiddleware',
     'django.middleware.csrf.CsrfViewMiddleware',
 
     'django.middleware.common.CommonMiddleware',
     'django.middleware.csrf.CsrfViewMiddleware',
+    'honeypot.middleware.HoneypotMiddleware',
     'django.contrib.auth.middleware.AuthenticationMiddleware'
             if "django.contrib.auth" in INSTALLED_APPS else None,
     'django_cas.middleware.CASMiddleware'
     'django.contrib.auth.middleware.AuthenticationMiddleware'
             if "django.contrib.auth" in INSTALLED_APPS else None,
     'django_cas.middleware.CASMiddleware'
index 2da1448..9291ce5 100644 (file)
@@ -3,3 +3,5 @@ CAS_VERSION = '1'
 
 SPONSORS_THUMB_WIDTH = 100
 SPONSORS_THUMB_HEIGHT = 56
 
 SPONSORS_THUMB_WIDTH = 100
 SPONSORS_THUMB_HEIGHT = 56
+
+HONEYPOT_FIELD_NAME='miut'
index a32c709..aa2a203 100644 (file)
@@ -17,6 +17,7 @@ PIPELINE_CSS = {
         'source_filenames': (
           'css/base.scss',
           'css/main.scss',
         'source_filenames': (
           'css/base.scss',
           'css/main.scss',
+          'css/form.scss',
           'catalogue/css/carousel.scss',
           'catalogue/css/layout.scss',
           'catalogue/css/lesson.scss',
           'catalogue/css/carousel.scss',
           'catalogue/css/layout.scss',
           'catalogue/css/lesson.scss',
index da1b7eb..758819b 100644 (file)
@@ -1,2 +1,3 @@
 CATALOGUE_PACKAGE = "catalogue/edukacjamedialna.zip"
 CATALOGUE_PACKAGE_STUDENT = "catalogue/edukacjamedialna_uczen.zip"
 CATALOGUE_PACKAGE = "catalogue/edukacjamedialna.zip"
 CATALOGUE_PACKAGE_STUDENT = "catalogue/edukacjamedialna_uczen.zip"
+CONTACT_FORMS_MODULE = 'edumed.contact_forms'
diff --git a/edumed/static/css/form.css b/edumed/static/css/form.css
new file mode 100644 (file)
index 0000000..878de75
--- /dev/null
@@ -0,0 +1,14 @@
+.submit-form th, .submit-form td {
+  padding: .3em;
+  vertical-align: top;
+  text-align: left; }
+.submit-form th {
+  max-width: 16em;
+  font-weight: normal; }
+.submit-form .required label:before {
+  content: "* ";
+  color: red; }
+.submit-form .errorlist {
+  padding: 0 0 0 1em;
+  margin: 0;
+  color: red; }
diff --git a/edumed/static/css/form.scss b/edumed/static/css/form.scss
new file mode 100755 (executable)
index 0000000..83c7938
--- /dev/null
@@ -0,0 +1,20 @@
+.submit-form {
+    th, td {
+        padding: .3em;
+        vertical-align: top;
+        text-align: left;
+    }
+    th {
+        max-width: 16em;
+        font-weight: normal;
+    }
+    .required label:before {
+        content: "* ";
+        color: red;
+    }
+    .errorlist {
+        padding: 0 0 0 1em;
+        margin: 0;
+        color: red;
+    }
+}
diff --git a/edumed/templates/contact/konkurs/mail_body.txt b/edumed/templates/contact/konkurs/mail_body.txt
new file mode 100644 (file)
index 0000000..10b2826
--- /dev/null
@@ -0,0 +1,10 @@
+Dziękujemy,
+
+Zgłoszenie na konkurs MediaLog na stronie {{ site_name }}
+zostało zarejestrowane.
+
+W razie jakichkolwiek wątpliwości prosimy o kontakt:
+http://edukacjamedialna.edu.pl/info/kontakt/
+
+-- 
+Wiadomość wysłana automatycznie. Prosimy na nią nie odpowiadać.
diff --git a/edumed/templates/contact/konkurs/mail_subject.txt b/edumed/templates/contact/konkurs/mail_subject.txt
new file mode 100644 (file)
index 0000000..386c1e6
--- /dev/null
@@ -0,0 +1 @@
+Zgłoszenie na konkurs MediaLog zostało zarejestrowane.
diff --git a/edumed/templates/contact/konkurs/thanks.html b/edumed/templates/contact/konkurs/thanks.html
new file mode 100644 (file)
index 0000000..357e398
--- /dev/null
@@ -0,0 +1,5 @@
+{% extends "contact/thanks.html" %}
+
+{% block contact_form_description %}
+<p>Dziękujemy, zgłoszenie na <a href="/info/konkurs/">konkurs MediaLog</a> zostało zarejestrowane.</p>
+{% endblock %}
diff --git a/edumed/templates/contact/sugestie/mail_body.txt b/edumed/templates/contact/sugestie/mail_body.txt
new file mode 100644 (file)
index 0000000..ad38005
--- /dev/null
@@ -0,0 +1,10 @@
+Dziękujemy,
+
+Zgłoszenie na stronie {{ site_name }}
+zostało przekazane koordynatorce projektu.
+
+W razie jakichkolwiek dodatkowych wątpliwości prosimy o kontakt:
+http://edukacjamedialna.edu.pl/info/kontakt/
+
+-- 
+Wiadomość wysłana automatycznie. Prosimy na nią nie odpowiadać.
diff --git a/edumed/templates/contact/sugestie/mail_subject.txt b/edumed/templates/contact/sugestie/mail_subject.txt
new file mode 100644 (file)
index 0000000..19fcbfa
--- /dev/null
@@ -0,0 +1 @@
+Zgłoszenie na stronie {{ site_name }} zostało zarejestrowane.
diff --git a/edumed/templates/contact/sugestie/thanks.html b/edumed/templates/contact/sugestie/thanks.html
new file mode 100644 (file)
index 0000000..5c89bba
--- /dev/null
@@ -0,0 +1,5 @@
+{% extends "contact/thanks.html" %}
+
+{% block contact_form_description %}
+<p>Dziękujemy, zgłoszenie zostało zarejestrowane.</p>
+{% endblock %}
index 303e011..3e99b30 100644 (file)
@@ -11,6 +11,7 @@ urlpatterns = patterns('',
     url(r'^info/(?P<url>.*)$', 'django.contrib.flatpages.views.flatpage',
         name="info"),
     url(r'^szukaj/', include('haystack.urls')),
     url(r'^info/(?P<url>.*)$', 'django.contrib.flatpages.views.flatpage',
         name="info"),
     url(r'^szukaj/', include('haystack.urls')),
+    url(r'^zglos/', include('contact.urls')),
 )
 
 
 )
 
 
index ea7ea79..a8b89af 100644 (file)
@@ -15,6 +15,8 @@ fnpdjango<0.2
 
 Feedparser
 
 
 Feedparser
 
+django-honeypot
+
 # Librarian
 lxml
 texml
 # Librarian
 lxml
 texml