From dfcf9b11ca2fc3173a3b6925198836b6ddaaa61c Mon Sep 17 00:00:00 2001 From: Radek Czajka Date: Fri, 21 Jun 2013 12:55:10 +0200 Subject: [PATCH 01/16] add lesson stubs --- catalogue/admin.py | 4 +- .../migrations/0012_auto__add_lessonstub.py | 96 +++++++++++++++++++ catalogue/models.py | 14 +++ .../catalogue/snippets/section_box.html | 10 +- catalogue/templatetags/catalogue_tags.py | 11 ++- 5 files changed, 130 insertions(+), 5 deletions(-) create mode 100644 catalogue/migrations/0012_auto__add_lessonstub.py diff --git a/catalogue/admin.py b/catalogue/admin.py index 0e3c635..43488ce 100755 --- a/catalogue/admin.py +++ b/catalogue/admin.py @@ -1,5 +1,5 @@ from django.contrib import admin -from .models import Attachment, Section, Lesson +from .models import Attachment, Section, Lesson, LessonStub class AttachmentInline(admin.TabularInline): model = Attachment @@ -10,3 +10,5 @@ class LessonAdmin(admin.ModelAdmin): admin.site.register(Section) admin.site.register(Lesson, LessonAdmin) +admin.site.register(LessonStub) + diff --git a/catalogue/migrations/0012_auto__add_lessonstub.py b/catalogue/migrations/0012_auto__add_lessonstub.py new file mode 100644 index 0000000..d8e53bb --- /dev/null +++ b/catalogue/migrations/0012_auto__add_lessonstub.py @@ -0,0 +1,96 @@ +# -*- 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 'LessonStub' + db.create_table('catalogue_lessonstub', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('section', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['catalogue.Section'], null=True, blank=True)), + ('level', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['curriculum.Level'])), + ('title', self.gf('django.db.models.fields.CharField')(max_length=255)), + ('type', self.gf('django.db.models.fields.CharField')(max_length=15, db_index=True)), + ('order', self.gf('django.db.models.fields.IntegerField')(db_index=True)), + )) + db.send_create_signal('catalogue', ['LessonStub']) + + + def backwards(self, orm): + # Deleting model 'LessonStub' + db.delete_table('catalogue_lessonstub') + + + models = { + 'catalogue.attachment': { + 'Meta': {'ordering': "['slug', 'ext']", 'unique_together': "(['lesson', 'slug', 'ext'],)", 'object_name': 'Attachment'}, + 'ext': ('django.db.models.fields.CharField', [], {'max_length': '15'}), + 'file': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'lesson': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['catalogue.Lesson']"}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '255'}) + }, + 'catalogue.lesson': { + 'Meta': {'ordering': "['section', 'level', 'order']", 'object_name': 'Lesson'}, + 'curriculum_courses': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['curriculum.CurriculumCourse']", 'symmetrical': 'False'}), + 'dc': ('jsonfield.fields.JSONField', [], {'default': "'{}'"}), + 'html_file': ('django.db.models.fields.files.FileField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'level': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['curriculum.Level']"}), + 'order': ('django.db.models.fields.IntegerField', [], {'db_index': 'True'}), + 'package': ('django.db.models.fields.files.FileField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + 'pdf': ('django.db.models.fields.files.FileField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + 'section': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['catalogue.Section']", 'null': 'True', 'blank': 'True'}), + 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '255'}), + 'student_package': ('django.db.models.fields.files.FileField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + 'student_pdf': ('django.db.models.fields.files.FileField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'type': ('django.db.models.fields.CharField', [], {'max_length': '15', 'db_index': 'True'}), + 'xml_file': ('django.db.models.fields.files.FileField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}) + }, + 'catalogue.lessonstub': { + 'Meta': {'ordering': "['section', 'level', 'order']", 'object_name': 'LessonStub'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'level': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['curriculum.Level']"}), + 'order': ('django.db.models.fields.IntegerField', [], {'db_index': 'True'}), + 'section': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['catalogue.Section']", 'null': 'True', 'blank': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'type': ('django.db.models.fields.CharField', [], {'max_length': '15', 'db_index': 'True'}) + }, + 'catalogue.part': { + 'Meta': {'object_name': 'Part'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'lesson': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['catalogue.Lesson']"}), + 'pdf': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), + 'student_pdf': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}) + }, + 'catalogue.section': { + 'Meta': {'ordering': "['order']", 'object_name': 'Section'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'order': ('django.db.models.fields.IntegerField', [], {}), + 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '255'}), + 'title': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}), + 'xml_file': ('django.db.models.fields.files.FileField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}) + }, + 'curriculum.curriculumcourse': { + 'Meta': {'ordering': "['slug']", 'object_name': 'CurriculumCourse'}, + 'accusative': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}) + }, + 'curriculum.level': { + 'Meta': {'ordering': "['order']", 'object_name': 'Level'}, + 'group': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '255'}) + } + } + + complete_apps = ['catalogue'] \ No newline at end of file diff --git a/catalogue/models.py b/catalogue/models.py index 652f972..8e6793f 100644 --- a/catalogue/models.py +++ b/catalogue/models.py @@ -250,3 +250,17 @@ class Part(models.Model): null=True, blank=True) student_pdf = models.FileField(upload_to="catalogue/part/student_pdf", null=True, blank=True) + + +class LessonStub(models.Model): + section = models.ForeignKey(Section, null=True, blank=True) + level = models.ForeignKey(Level) + title = models.CharField(max_length=255) + type = models.CharField(max_length=15, db_index=True) + order = models.IntegerField(db_index=True) + + class Meta: + ordering = ['section', 'level', 'order'] + + def __unicode__(self): + return self.title diff --git a/catalogue/templates/catalogue/snippets/section_box.html b/catalogue/templates/catalogue/snippets/section_box.html index 84f1eda..3d265bb 100755 --- a/catalogue/templates/catalogue/snippets/section_box.html +++ b/catalogue/templates/catalogue/snippets/section_box.html @@ -17,9 +17,13 @@ diff --git a/catalogue/templatetags/catalogue_tags.py b/catalogue/templatetags/catalogue_tags.py index 7003dfe..c642f18 100755 --- a/catalogue/templatetags/catalogue_tags.py +++ b/catalogue/templatetags/catalogue_tags.py @@ -24,7 +24,16 @@ def catalogue_section_buttons(): @register.inclusion_tag("catalogue/snippets/section_box.html") def section_box(section): lessons = SortedDict() - for lesson in section.lesson_set.all(): + lesson_lists = [alist for alist in [ + list(section.lesson_set.all()), + list(section.lessonstub_set.all()) + ] if alist] + while lesson_lists: + min_index, min_list = min(enumerate(lesson_lists), key=lambda x: x[1][0].order) + lesson = min_list.pop(0) + if not min_list: + lesson_lists.pop(min_index) + if lesson.level not in lessons: newdict = SortedDict() newdict['synthetic'] = [] -- 2.20.1 From ebab887bba6bcfbd335bfb763f7238fc67339962 Mon Sep 17 00:00:00 2001 From: Radek Czajka Date: Fri, 21 Jun 2013 12:59:17 +0200 Subject: [PATCH 02/16] Fix error in a name. --- .../img/carousel/katarzyna-wlodarczyk.jpg} | Bin .../templates/catalogue/snippets/carousel.html | 2 +- edumed/templates/home.html | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename catalogue/static/{carousel/img1.jpg => catalogue/img/carousel/katarzyna-wlodarczyk.jpg} (100%) diff --git a/catalogue/static/carousel/img1.jpg b/catalogue/static/catalogue/img/carousel/katarzyna-wlodarczyk.jpg similarity index 100% rename from catalogue/static/carousel/img1.jpg rename to catalogue/static/catalogue/img/carousel/katarzyna-wlodarczyk.jpg diff --git a/catalogue/templates/catalogue/snippets/carousel.html b/catalogue/templates/catalogue/snippets/carousel.html index 9df2823..2adc9e2 100755 --- a/catalogue/templates/catalogue/snippets/carousel.html +++ b/catalogue/templates/catalogue/snippets/carousel.html @@ -4,7 +4,7 @@ {% url "info" "jak-korzystac/" as jak %} diff --git a/edumed/templates/home.html b/edumed/templates/home.html index 49907fe..ac03e7d 100755 --- a/edumed/templates/home.html +++ b/edumed/templates/home.html @@ -43,6 +43,7 @@
  • Pobierz wszystkie lekcje w wersji dla ucznia
  • Słowniczek
  • Metody edukacyjne
  • +
  • Infografiki
  • Polityka prywatności i ciasteczka
  • -- 2.20.1 From 81924fe71a34d654c68fe238ec4d43ca26ca0882 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Aleksander=20=C5=81ukasz?= Date: Mon, 2 Sep 2013 10:25:24 +0200 Subject: [PATCH 14/16] Additional link --- catalogue/templates/catalogue/lesson/project/lesson_detail.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/catalogue/templates/catalogue/lesson/project/lesson_detail.html b/catalogue/templates/catalogue/lesson/project/lesson_detail.html index ed36341..88e4a34 100755 --- a/catalogue/templates/catalogue/lesson/project/lesson_detail.html +++ b/catalogue/templates/catalogue/lesson/project/lesson_detail.html @@ -4,7 +4,7 @@

    Projekt

    -

    To jest projekt w ramach tematu +

    To jest projekt w ramach tematu {{ object.section }}{% if object.level.slug = "liceum" %} (na poziomie zaawansowanym) {% endif %}. -- 2.20.1 From 5fd8cacf1c73a8670d45406b7214a59eedaff07f Mon Sep 17 00:00:00 2001 From: Radek Czajka Date: Mon, 7 Oct 2013 15:37:24 +0200 Subject: [PATCH 15/16] Add formsets to contact forms, add WTEM form. --- contact/forms.py | 14 +++- contact/views.py | 16 ++++- edumed/contact_forms.py | 47 +++++++++++++ edumed/settings.d/50-static.py | 1 + edumed/static/js/formset.js | 30 +++++++++ edumed/templates/contact/wtem/form.html | 66 +++++++++++++++++++ edumed/templates/contact/wtem/mail_body.txt | 18 +++++ .../templates/contact/wtem/mail_subject.txt | 1 + edumed/templates/contact/wtem/thanks.html | 14 ++++ 9 files changed, 202 insertions(+), 5 deletions(-) create mode 100755 edumed/static/js/formset.js create mode 100755 edumed/templates/contact/wtem/form.html create mode 100755 edumed/templates/contact/wtem/mail_body.txt create mode 100755 edumed/templates/contact/wtem/mail_subject.txt create mode 100755 edumed/templates/contact/wtem/thanks.html diff --git a/contact/forms.py b/contact/forms.py index 0279e12..e369e95 100644 --- a/contact/forms.py +++ b/contact/forms.py @@ -33,12 +33,22 @@ class ContactForm(forms.Form): required_css_class = 'required' contact = forms.CharField(max_length=128) - def save(self, request): + 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 + 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'], diff --git a/contact/views.py b/contact/views.py index d18598c..26ccf60 100644 --- a/contact/views.py +++ b/contact/views.py @@ -14,14 +14,24 @@ def form(request, form_tag): raise Http404 if request.method == 'POST': form = form_class(request.POST, request.FILES) - if form.is_valid(): - form.save(request) + formsets = [] + valid = form.is_valid() + for formset in getattr(form, 'form_formsets', ()): + fset = formset(request.POST, request.FILES) + if not fset.is_valid(): + valid = False + formsets.append(fset) + if valid: + form.save(request, formsets) return redirect('contact_thanks', form_tag) else: form = form_class(initial=request.GET) + formsets = [] + for formset in getattr(form, 'form_formsets', ()): + formsets.append(formset()) return render(request, ['contact/%s/form.html' % form_tag, 'contact/form.html'], - {'form': form} + {'form': form, 'formsets': formsets} ) diff --git a/edumed/contact_forms.py b/edumed/contact_forms.py index 89e5121..f688e5b 100644 --- a/edumed/contact_forms.py +++ b/edumed/contact_forms.py @@ -81,3 +81,50 @@ class UdzialForm(ContactForm): contact = forms.EmailField(label=u'Adres e-mail', max_length=128) telefon = forms.CharField(label=u'Telefon', max_length=32) uczestnicy = forms.IntegerField(label=u'Przewidywana liczba uczestników zajęć') + + +class WTEMStudentForm(forms.Form): + first_name = forms.CharField(label=u'Imię', max_length=128) + last_name = forms.CharField(label=u'Nazwisko', max_length=128) + email = forms.EmailField(label=u'Adres e-mail', max_length=128) + form_tag = "student" + +class NoEmptyFormsAllowedBaseFormSet(forms.formsets.BaseFormSet): + """ + Won't allow formset_factory to be submitted with no forms + """ + def clean(self): + for form in self.forms: + if form.cleaned_data: + return + raise forms.ValidationError(u"Proszę podać dane przynajmniej jednego ucznia.") + +class WTEMForm(ContactForm): + form_tag = "wtem" + form_title = u"WTEM - rejestracja uczestników" + submit_label = u"Wyślij zgłoszenie" + form_formsets = (forms.formsets.formset_factory(WTEMStudentForm, formset=NoEmptyFormsAllowedBaseFormSet),) + + contact = forms.EmailField(label=u'Adres e-mail opiekuna/opiekunki', max_length=128) + imie = forms.CharField(label=u'Imię', max_length=128) + nazwisko = forms.CharField(label=u'Nazwisko', max_length=128) + function = forms.CharField(label=u'Pełniona funkcja', max_length=255) + institution = forms.CharField(label=u'Nazwa instytucji', max_length=255) + institution_address = forms.CharField(label=u'Adres instytucji', widget=forms.Textarea, max_length=1000) + institution_email = forms.EmailField(label=u'Adres e-mail instytucji', max_length=128) + institution_phone = forms.CharField(label=u'Telefon do instytucji', max_length=32) + institution_www = forms.URLField(label=u'Strona WWW instytucji', max_length=255, required=False) + + zgoda_regulamin = forms.BooleanField( + label=u'Znam i akceptuję regulamin Wielkiego Turnieju Edukacji Medialnej.', + help_text=u'Zobacz regulamin Wielkiego Turnieju Edukacji Medialnej.' + ) + potw_uczniowie = forms.BooleanField( + label=u'Potwierdzam, że zgłoszeni Uczestnicy/Uczestniczki w chwili rejestracji są uczniami/uczennicami szkoły ponadgimnazjalnej.', + #help_text=u'Zobacz regulamin Wielkiego Turnieju Edukacji Medialnej.' + ) + zgoda_informacje = forms.BooleanField( + label=u'Wyrażam zgodę na otrzymywanie informacji od Fundacji Nowoczesna Polska związanych z edukacją medialną.', + required=False + ) + diff --git a/edumed/settings.d/50-static.py b/edumed/settings.d/50-static.py index 4013a66..b6d9591 100644 --- a/edumed/settings.d/50-static.py +++ b/edumed/settings.d/50-static.py @@ -40,6 +40,7 @@ PIPELINE_JS = { 'catalogue/js/lesson.js', 'sponsors/js/sponsors.js', 'curriculum/curriculum.js', + 'js/formset.js', ), 'output_filename': 'compressed/base.js', }, diff --git a/edumed/static/js/formset.js b/edumed/static/js/formset.js new file mode 100755 index 0000000..7a4657f --- /dev/null +++ b/edumed/static/js/formset.js @@ -0,0 +1,30 @@ +(function($) { + $(function() { + + +function cloneMore(selector, type) { + var newElement = $(selector).clone(true); + var total = $('#id_' + type + '-TOTAL_FORMS').val(); + newElement.find(':input').each(function() { + var name = $(this).attr('name').replace('__prefix__', total); + var id = 'id_' + name; + $(this).attr({'name': name, 'id': id}); + }); + newElement.find('label').each(function() { + var newFor = $(this).attr('for').replace('__prefix__', total); + $(this).attr('for', newFor); + }); + newElement.attr({'style': '', 'id': ''}); + total++; + $('#id_' + type + '-TOTAL_FORMS').val(total); + $(selector).before(newElement); +} + + + + $('.add_more').click(function() { + cloneMore($(this).data('selector'), $(this).data('prefix')); + }); + + }); +})(jQuery); diff --git a/edumed/templates/contact/wtem/form.html b/edumed/templates/contact/wtem/form.html new file mode 100755 index 0000000..ca3b930 --- /dev/null +++ b/edumed/templates/contact/wtem/form.html @@ -0,0 +1,66 @@ +{% extends "base.html" %} +{% load chunks %} + +{% block title %}{{ form.form_title }}{% endblock %} + +{% block body %} + + + + + + +

    {% block contact_form_title %}{{ form.form_title }}{% endblock %}

    + +
    + {% block contact_form_description %} + {% chunk "contact_form__"|add:form.form_tag %} + {% endblock %} +
    + +
    + {% csrf_token %} +

    Dane Opiekuna/Opiekunki i instytucji zgłaszającej Uczestnika:

    + + {{ form.as_table }} +
    + + {% for formset in formsets %} + + {{ formset.management_form }} + +
      + {% for err in formset.non_form_errors %} +
    • {{ err }}
    • + {% endfor %} +
    + + {% for form in formset.forms %} +

    Dane Uczestnika/Uczestniczki:

    + + + {{ form.as_table }} +
    + {% endfor %} + + + + + + + {% endfor %} + +

    + +

    +
    + + +{% endblock %} diff --git a/edumed/templates/contact/wtem/mail_body.txt b/edumed/templates/contact/wtem/mail_body.txt new file mode 100755 index 0000000..0c20f5f --- /dev/null +++ b/edumed/templates/contact/wtem/mail_body.txt @@ -0,0 +1,18 @@ +Dziękujemy za rejestrację w Wielkim Turnieju Edukacji Medialnej. +Do udziału zostały zgłoszone następujące osoby: +{% for student in contact.body.student %} +* {{ student.first_name }} {{ student.last_name }}{% endfor %} + +Pierwszy etap Turnieju odbędzie się 21 listopada 2013 r. o godz. 15.30. +Po zakończeniu rejestracji (4 listopada) każdy Uczestnik otrzyma maila +z indywidualną instrukcją dotyczącą udziału w I etapie Turnieju. + +Wszystkie ogłoszenia związane z Turniejem będą publikowane na stronie +http://edukacjamedialna.edu.pl/WTEM. W razie pytań lub wątpliwości +możesz kontaktować się z nami pisząc na adres +edukacjamedialna@nowoczesnapolska.org.pl. + +Z pozdrowieniami + +Zespół Edukacji Medialnej +Fundacja Nowoczesna Polska diff --git a/edumed/templates/contact/wtem/mail_subject.txt b/edumed/templates/contact/wtem/mail_subject.txt new file mode 100755 index 0000000..15f682a --- /dev/null +++ b/edumed/templates/contact/wtem/mail_subject.txt @@ -0,0 +1 @@ +Dziękujemy za rejestrację w Wielkim Turnieju Edukacji Medialnej. diff --git a/edumed/templates/contact/wtem/thanks.html b/edumed/templates/contact/wtem/thanks.html new file mode 100755 index 0000000..9ad56ff --- /dev/null +++ b/edumed/templates/contact/wtem/thanks.html @@ -0,0 +1,14 @@ +{% extends "contact/thanks.html" %} + +{% block contact_form_description %} +

    Dziękujemy za rejestrację w Wielkim Turnieju Edukacji Medialnej.

    + +

    Na adres adres e-mail Opiekuna została wysłana wiadomość potwierdzająca +rejestrację.

    + +

    Pierwszy etap Turnieju odbędzie się 21 listopada 2013 r. o godz. 15.30.
    +Serdecznie zapraszamy do udziału.

    + +

    Zespół Edukacji Medialnej
    +Fundacja Nowoczesna Polska

    +{% endblock %} -- 2.20.1 From 284217e8b8297ccda99551e84750c5835319bb5c Mon Sep 17 00:00:00 2001 From: Radek Czajka Date: Mon, 7 Oct 2013 15:37:34 +0200 Subject: [PATCH 16/16] Menu change. --- edumed/templates/base.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/edumed/templates/base.html b/edumed/templates/base.html index 6233cf3..52b34ce 100644 --- a/edumed/templates/base.html +++ b/edumed/templates/base.html @@ -42,7 +42,7 @@
  • Lekcje
  • Kompetencje
  • Współpraca
  • -
  • Konkurs
  • +
  • Turniej
  • Wesprzyj nas
  • O nas
  • Kontakt
  • -- 2.20.1