ścieżki kopernika - test form
authorJan Szejko <janek37@gmail.com>
Thu, 25 May 2017 12:26:03 +0000 (14:26 +0200)
committerJan Szejko <janek37@gmail.com>
Fri, 26 May 2017 07:05:54 +0000 (09:05 +0200)
16 files changed:
catalogue/static/catalogue/css/layout.css
catalogue/static/catalogue/css/layout.scss
contact/forms.py
contact/models.py
contact/templates/contact/form.html
contact/urls.py
contact/views.py
edumed/contact_forms.py
edumed/static/css/form.css
edumed/static/css/form.scss
edumed/templates/contact/sciezki-kopernika-test/form.html [new file with mode: 0644]
edumed/templates/contact/sciezki-kopernika-test/mail_subject.txt [new file with mode: 0644]
edumed/templates/contact/sciezki-kopernika-test/results.html [new file with mode: 0644]
edumed/templates/contact/sciezki-kopernika-test/results_email.txt [new file with mode: 0644]
edumed/templatetags/__init__.py [new file with mode: 0644]
edumed/templatetags/inline_stylesheet.py [new file with mode: 0644]

index acf699d..30e091b 100644 (file)
@@ -2,11 +2,11 @@
 .box-button {
   background-color: #ed7831;
   border-radius: 0.9375em; }
 .box-button {
   background-color: #ed7831;
   border-radius: 0.9375em; }
-  .box-button .dl-button {
+  .box-button .dl-button, .box-button .nice-button {
     color: white;
     padding: 1.0625em 0.75em 1.0625em 0.75em; }
 
     color: white;
     padding: 1.0625em 0.75em 1.0625em 0.75em; }
 
-.dl-button {
+.dl-button, .nice-button {
   color: #363a3e;
   display: block;
   font-weight: bold;
   color: #363a3e;
   display: block;
   font-weight: bold;
index 230e4aa..637bd50 100755 (executable)
@@ -4,12 +4,12 @@ $new_black: #363a3e;
 .box-button {
     background-color: #ed7831;
     border-radius: 15*$px;
 .box-button {
     background-color: #ed7831;
     border-radius: 15*$px;
-    .dl-button {
+    .dl-button, .nice-button {
         color: white;
         padding: 17*$px 12*$px 17*$px 12*$px;
     }
 }
         color: white;
         padding: 17*$px 12*$px 17*$px 12*$px;
     }
 }
-.dl-button {
+.dl-button, .nice-button {
     color: $new_black;
     display: block;
     font-weight: bold;
     color: $new_black;
     display: block;
     font-weight: bold;
index 2cea310..62957ad 100644 (file)
@@ -3,6 +3,7 @@ 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.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.core.validators import validate_email
 from django import forms
 from django.template.loader import render_to_string
@@ -33,6 +34,7 @@ class ContactForm(forms.Form):
     form_title = _('Contact form')
     submit_label = _('Submit')
     admin_list = None
     form_title = _('Contact form')
     submit_label = _('Submit')
     admin_list = None
+    result_page = False
 
     required_css_class = 'required'
     contact = forms.CharField(max_length=128)
 
     required_css_class = 'required'
     contact = forms.CharField(max_length=128)
@@ -52,7 +54,7 @@ class ContactForm(forms.Form):
                         sub_body[name] = value
                 if sub_body:
                     body.setdefault(f.form_tag, []).append(sub_body)
                         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 = Contact.objects.create(
             body=body,
             ip=request.META['REMOTE_ADDR'],
@@ -91,10 +93,18 @@ class ContactForm(forms.Form):
                     'contact/%s/mail_subject.txt' % self.form_tag,
                     'contact/mail_subject.txt', 
                 ], dictionary, context).strip()
                     '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)
+            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
             send_mail(mail_subject, mail_body, 'no-reply@%s' % site.domain, [contact.contact], fail_silently=True)
 
         return contact
index 1c92610..8d89c8d 100644 (file)
@@ -1,5 +1,6 @@
 # -*- coding: utf-8 -*-
 import yaml
 # -*- 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 django.db import models
 from django.utils.encoding import smart_unicode
 from django.utils.translation import ugettext_lazy as _
@@ -30,6 +31,11 @@ class Contact(models.Model):
     def __unicode__(self):
         return unicode(self.created_at)
 
     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)
 
 class Attachment(models.Model):
     contact = models.ForeignKey(Contact)
index 584629a..d27c871 100644 (file)
     <form method="POST" action="." enctype="multipart/form-data" class="submit-form">
     {% csrf_token %}
     {% render_honeypot_field %}
     <form method="POST" action="." enctype="multipart/form-data" class="submit-form">
     {% csrf_token %}
     {% render_honeypot_field %}
-    <table>
-        {{ form.as_table }}
-        <tr><td></td><td><button>{% block contact_form_submit %}{{ form.submit_label }}{% endblock %}</button></td></tr>
-    </table>
+    {% 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 %}
     </form>
 
 {% endblock %}
index 16033a1..f2ef944 100644 (file)
@@ -7,4 +7,5 @@ urlpatterns = patterns(
     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'^(?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'),
 )
 )
index 5a2f2ae..82e0347 100644 (file)
@@ -8,7 +8,7 @@ from fnpdjango.utils.views import serve_file
 from honeypot.decorators import check_honeypot
 
 from .forms import contact_forms
 from honeypot.decorators import check_honeypot
 
 from .forms import contact_forms
-from .models import Attachment
+from .models import Attachment, Contact
 
 
 @check_honeypot
 
 
 @check_honeypot
@@ -33,8 +33,11 @@ def form(request, form_tag, force_enabled=False):
             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()):
             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()):
-            form.save(request, formsets.values())
-            return redirect('contact_thanks', form_tag)
+            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()}
 
     else:
         formsets = {prefix: formset_class(prefix=prefix) for prefix, formset_class in formset_classes.iteritems()}
 
@@ -55,6 +58,24 @@ def thanks(request, form_tag):
         {'base_template': getattr(form_class, 'base_template', None)})
 
 
         {'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)
 @permission_required('contact.change_attachment')
 def attachment(request, contact_id, tag):
     attachment = get_object_or_404(Attachment, contact_id=contact_id, tag=tag)
index f19d591..29f25b4 100644 (file)
@@ -649,3 +649,292 @@ class CybernauciAnkietaForm(ContactForm):
     pyt14 = textarea_field(
         u'14. W jaki sposób na co dzień dbasz o swój rozwój jako trenera/trenerki, '
         u'osoby prowadzącej warsztaty czy inne formy szkoleniowe?')
     pyt14 = textarea_field(
         u'14. W jaki sposób na co dzień dbasz o swój rozwój jako trenera/trenerki, '
         u'osoby prowadzącej warsztaty czy inne formy szkoleniowe?')
+
+
+def quiz_question(label, choices):
+    return forms.TypedChoiceField(label=label, choices=choices, coerce=int, widget=forms.RadioSelect)
+
+
+def make_link(text, url):
+    return u'<a href="%s">%s</a>' % (url, text)
+
+
+class SciezkiKopernikaTestForm(ContactForm):
+    def __init__(self, *args, **kwargs):
+        super(SciezkiKopernikaTestForm, self).__init__(*args, **kwargs)
+        self.label_suffix = ''
+
+    result_page = True
+    form_tag = 'sciezki-kopernika-test'
+    form_title = u'Test'
+    submit_label = u'Wyślij'
+
+    contact = forms.EmailField(label=u'Adres e-mail, na który przyślemy informację o wynikach')
+    pyt1 = quiz_question(
+        label=u'1) Na stronie portalu internetowego opublikowano wpis o treści '
+              u'„Nie wszyscy muzułmanie to terroryści, ale wszyscy terroryści to muzułmanie”. '
+              u'Komentarz podlega moderacji i powinien:',
+        choices=[
+            (1, u'zostać zachowany, ponieważ jest prywatną opinią korzystającą z wolności słowa,'),
+            (0, u'zostać zachowany, ponieważ informuje o fakcie,'),
+            (2, u'zostać usunięty, ponieważ jest wprowadzającą w błąd interpretacją faktów.'),
+        ])
+    pyt2 = quiz_question(
+        label=u'2) Aby przygotować podcast, należy posiadać przynajmniej:',
+        choices=[
+            (0, u'półprofesjonalny mikrofon radiowy, z wbudowanym interfejsem dźwiękowym, '
+                u'komercyjne oprogramowanie typu DAW, średnio-zaawansowane umiejętności cyfrowej obróbki dźwięku,'),
+            (1, u'urządzenie do nagrywania dźwięku, laptop, oprogramowanie dedykowane do tworzenia podcastów,'),
+            (2, u'urządzenie do nagrywania dźwięku, podstawowe oprogramowanie do edycji dźwięku, '
+                u'podstawowe umiejętności cyfrowej obróbki dźwięku.')])
+    pyt3 = quiz_question(
+        label=u'3) Muzeum cyfrowe chce udostępnić skan XIV-wiecznego kodeksu. '
+              u'Zgodnym z ideą domeny publicznej sposobem jego udostępnienia będzie:',
+        choices=[
+            (0, u'udostępnienie go na licencji Creative Commons,'),
+            (2, u'udostępnienie go bez licencji z czytelnym wskazaniem praw do dowolnego wykorzystania,'),
+            (1, u'udostępnienie go w pliku jakości produkcyjnej.')])
+    pyt4 = quiz_question(
+        label=u'4) Aby uniknąć możliwości podejrzenia przez niepowołane osoby, jakie strony internetowe '
+              u'odwiedzałeś ostatnio, powinieneś/powinnaś:',
+        choices=[
+            (0, u'ustawić opcję otwierania nowej sesji przeglądarki bez wyświetlania ostatnio używanych kart '
+                u'oraz regularnie czyścić historię wyszukiwania,'),
+            (2, u'wylogowywać się lub blokować ekran za każdym razem, kiedy odchodzisz od komputera, tabletu '
+                u'lub odkładasz gdzieś telefon, regularnie czyścić dane zgromadzone przez przeglądarkę internetową,'),
+            (1, u'wylogowywać się lub blokować ekran za każdym razem, kiedy odchodzisz od komputera, tabletu '
+                u'lub odkładasz gdzieś telefon, regularnie czyścić historię przeglądanych stron.')])
+    pyt5 = quiz_question(
+        label=u'5) Komentarz opublikowany w internecie ma taką samą wartość bez względu na to, '
+              u'czy jest anonimowy czy podpisany imieniem i nazwiskiem:',
+        choices=[
+            (0, u'tak, ze względu na zasadę wolności słowa,'),
+            (2, u'to zależy od jego treści i kontekstu, w którym go opublikowano,'),
+            (1, u'tak, z punktu widzenia odpowiedzialności prawnej. [poprawna]')])
+    pyt6 = quiz_question(
+        label=u'6) Wraz z grupą osób zamierzasz przygotować cyfrową opowieść (narrację) na temat współczesnych '
+              u'nastolatków i ich stosunku do szkoły. Żeby praca była efektywna, a jej rezultat efektowny, warto '
+              u'zorganizować wspólną pracę w następujących krokach:',
+        choices=[
+            (2, u'przeprowadzić wspólną dyskusję odnośnie tematu opowieści, wybrać jeden, ustalić, co należy zrobić, '
+                u'podzielić zadania w grupie i przygotować scenariusz narracji (opisać poszczególne sceny, co się '
+                u'w nich znajdzie, co będzie potrzebne do ich przygotowania),'),
+            (0, u'zgromadzić jak najwięcej materiałów wideo i zdjęć, wybrać oprogramowanie do obróbki wideo i wspólnie '
+                u'decydować o kolejności scen i zawartości opowieści,'),
+            (1, u'wybrać temat opowieści, zgromadzić jak najwięcej filmików i zdjęć, podzielić się zadaniami w grupie, '
+                u'zmontować narrację z części przygotowanych przez uczestników zespołu.')])
+    pyt7 = quiz_question(
+        label=u'7) Firma telekomunikacyjna wykorzystuje boty do automatycznego odpowiadania na pytania klientów '
+              u'zadawane przez Facebooka. Boty zwracają się do wszystkich po imieniu. Kiedy użytkownik, który nie '
+              u'życzy sobie tego nie życzy, wyraża swoje niezadowolenie z takiej formy rozmowy, firma:',
+        choices=[
+            (2, u'przeprosić użytkownika, szanując preferowane przez niego reguły komunikacji,'),
+            (0, u'zignorować użytkownika odwołując się do zasad netykiety,'),
+            (1, u'zareagować zgodnie z wypracowanymi wewnętrznie zasadami komunikacji.')])
+    pyt8 = quiz_question(
+        label=u'8) Jesteś członkiem/członkinią grupy, która przygotowuje aplikację, mającą ułatwić osobom '
+              u'niepełnosprawnym poruszanie się po Twojej miejscowości. Oprogramowanie będzie m.in. informować, '
+              u'czy przy określonej instytucji, firmie, sklepie, znajdują się miejsca parkingowe '
+              u'dla niepełnosprawnych i ile ich jest. Aby aplikacja działała prawidłowo, powinieneś/powinnaś:',
+        choices=[
+            (1, u'przygotować listę najważniejszych obiektów w Twoim mieście i skontaktować się z ich administracją, '
+                u'pytając o liczbę miejsc parkingowych,'),
+            (0, u'poszukać informacji o dostępnych miejscach parkingowych na stronach instytucji, firm i sklepów,'),
+            (2, u'skontaktować się z administracją obiektów, o których będzie informować aplikacja, udać się również '
+                u'do tych obiektów, aby potwierdzić ilość dostępnych miejsc, spróbować zgromadzić informacje o tym, '
+                u'jak często miejsca parkingowe są zajmowane przez ludzi pełnosprawnych.')])
+    pyt9 = quiz_question(
+        label=u'9) Pojęcie „niewidzialnej pracy” może dotyczyć:',
+        choices=[
+            (2, u'moderatorów mediów społecznościowych zatrudnianych w krajach o niskich kosztach pracy, [najlepsze]'),
+            (1, u'użytkowników serwisów społecznościowych publikujących codziennie i bez wynagrodzenia własne '
+                u'materiały w tym serwisie, [dobre]'),
+            (0, u'informatyków budujących rozwiązania IT dla firm. [złe]')])
+
+    pyt10 = quiz_question(
+        label=u'10) Możesz uważać, że informacje, do których docierasz, są wiarygodne, ponieważ:',
+        choices=[
+            (1, u'pojawiają się w wielu telewizyjnych serwisach informacyjnych, na profilach społecznościowych '
+                u'moich znajomych i w różnorodnych internetowych serwisach informacyjnych, wszędzie przedstawiane '
+                u'są w podobny sposób,'),
+            (2, u'pojawiają się w wielu serwisach informacyjnych, na profilach moich znajomych, zawierają odnośniki '
+                u'do oryginalnych źródeł, do których można dotrzeć,'),
+            (0, u'pojawiają się na profilach wielu moich znajomych w serwisach społecznościowych i '
+                u'w kilku internetowych serwisach informacyjnych.')])
+    pyt11 = quiz_question(
+        label=u'11) W pewnym mieście prokuratura bada umowy z wykonawcami projektów budżetu obywatelskiego. '
+              u'Nikomu, jak dotąd, nie postawiono zarzutów. Która postać tytułu newsa opublikowanego '
+              u'na lokalnym portalu internetowym będzie najbardziej zgodna z zasadami etyki dziennikarskiej?',
+        choices=[
+            (1, u'„Budżet obywatelski: niejasne umowy z wykonawcami?”,'),
+            (2, u'„Prokuratura zbada umowy z wykonawcami projektów budżetu obywatelskiego.”,'),
+            (0, u'„Zobacz, które firmy mogły obłowić się na projektach budżetu obywatelskiego!”.')])
+    pyt12 = quiz_question(
+        label=u'12) Dołączyłeś/-aś do grupy, która zbiera informacje o problemach dotyczących młodych ludzi '
+              u'w Twojej okolicy. Zamierzacie zaprezentować zgromadzone informacje w interesujący sposób, '
+              u'tak by zainteresować lokalne media, służby miejskie, zwykłych obywateli i waszych rówieśników. '
+              u'Grupa nie ma możliwości regularnego spotykania się, dlatego wybraliście pracę wyłącznie '
+              u'przez internet. Który zestaw narzędzi pozwoli wam na jak najlepszą, wspólną pracę?',
+        choices=[
+            (0, u'mail grupowy, komunikator tekstowy (np. Messenger), oprogramowanie do tworzenia podcastów, '
+                u'stacjonarne narzędzie do tworzenia prezentacji (np. Power Point),'),
+            (1, u'mail grupowy, komunikator tekstowy zespołu (np. Slack), narzędzie do kolektywnego tworzenia '
+                u'map myśli (np. Coggle), blog redagowany przez wszystkich uczestników projektu, aplikacja do '
+                u'synchronizowania plików w chmurze (np. Dropbox), narzędzie do grupowej komunikacji za pomocą wideo '
+                u'(dyskusyjna) (np. Skype),'),
+            (2, u'aplikacja do zarządzania zadaniami zespołu i terminami do wykonania (np. Wunderlist), '
+                u'narzędzie do tworzenia kolektywnych notatek (np. OneNote) lub wspólnej pracy z tekstem '
+                u'(np. EtherPad, Google Dokumenty), grupa w serwisie społecznościowym lub tekstowy komunikator '
+                u'zespołu (np. Messenger lub Slack), narzędzia do gromadzenia lub prezentowania materiałów '
+                u'(np. wspólny blog, kanał w serwisie społecznościowym).')])
+    pyt13 = quiz_question(
+        label=u'13) Poniżej podano wybrane cechy hasła opublikowanego w Wikipedii. '
+              u'Która z nich jest najbardziej pomocna przy analizie jakości hasła?',
+        choices=[
+            (0, u'liczba edycji hasła,'),
+            (1, u'długość i struktura hasła,'),
+            (2, u'obecność i jakość przypisów.')])
+    pyt14 = quiz_question(
+        label=u'14) Na przeglądanej stronie internetowej znalazłeś/-aś interesującą grafikę, którą chciał(a)byś '
+              u'wykorzystać przygotowywanej cyfrowej narracji. Nie jest ona jednak podpisana. Co robisz?',
+        choices=[
+            (0, u'podpisuję grafikę adresem strony, na której ją znalazłem/-am,'),
+            (1, u'korzystam z opcji wyszukiwania obrazem w wyszukiwarce grafiki, chcąc znaleźć inne strony, '
+                u'gdzie pojawiła się grafika,'),
+            (2, u'korzystam z opcji wyszukiwania obrazem, a jeśli to się nie powiedzie, skontaktuję się '
+                u'z administratorem strony, na której znalazłem/-am grafikę, pytając o autora; przeglądam także '
+                u'informacje o stronie, szukając ewentualnych informacji o zasadach publikacji treści; być może '
+                u'autor informuje, że wszystkie grafiki są jego autorstwa.')])
+    pyt15 = quiz_question(
+        label=mark_safe(
+            u'15) W nieistniejącym języku programowania TEST dana jest funkcja zapisana w następujący sposób:'
+            u'<p><code>funkcja f(a) { wyświetl a + b;<br>'
+            u'}</code></p>'
+            u'<strong>Przeczytaj uważnie kod i zastanów się, jak działa ta funkcja.'
+            u'Główną wadą tego kodu jest przetwarzanie brakującego argumentu:</strong>'),
+        choices=[
+            (2, u'b,'),
+            (1, u'b będącego dowolną liczbą,'),
+            (0, u'f.')])
+    pyt16 = quiz_question(
+        label=u'16) Przygotowujesz teledysk do utworu nagranego przez twój zespół. Efekt swojej pracy opublikujesz '
+              u'na kanale zespołu na YouTube. Teledysk nie może łamać praw autorskich, w przeciwnym razie zostanie '
+              u'usunięty z serwisu. W teledysku możesz wykorzystać zdjęcia, ikony, fragmenty filmów:',
+        choices=[
+            (1, mark_safe(
+                u'znalezionych w wyszukiwarce serwisu Flickr na licencji %s, przygotowanych przez ciebie, '
+                u'ściągniętych z serwisu %s,' % (
+                    make_link(u'CC BY-SA', 'https://www.flickr.com/creativecommons/by-sa-2.0/'),
+                    make_link(u'The Noun Project', 'https://thenounproject.com')))),
+            (2, mark_safe(
+                u'znalezionych w wyszukiwarce serwisu Flickr na licencji %s, przygotowanych przez ciebie, '
+                u'ściągniętych z %s,' % (
+                    make_link(u'CC-BY', 'https://www.flickr.com/creativecommons/by-2.0/'),
+                    make_link(u'serwisu ze zdjęciami NASA',
+                              'https://www.nasa.gov/multimedia/imagegallery/index.html')))),
+            (0, mark_safe(
+                u'znalezionych w wyszukiwarce serwisu Flickr na licencji %s, przygotowanych przez ciebie, '
+                u'ściągniętych z wyszukiwarki grafiki Google.' %
+                make_link('CC-BY-NC', 'https://www.flickr.com/creativecommons/by-nc-2.0/')))])
+    pyt17 = quiz_question(
+        label=mark_safe(
+            u'17) Muzeum cyfrowe udostępniło skan druku propagandowego z pierwszej połowy XVII w. '
+            u'w humorystyczny sposób przedstawiający strony angielskiej wojny domowej (trwającej z przerwami '
+            u'między 1642-1651 rokiem):'
+            u'<p><a href="https://commons.wikimedia.org/wiki/File:Engl-Bürgerkrieg.JPG">'
+            u'<img src="https://upload.wikimedia.org/wikipedia/commons/c/c6/Engl-B%C3%BCrgerkrieg.JPG"></a></p>'
+            u'<p><a href="https://commons.wikimedia.org/wiki/File:Engl-Bürgerkrieg.JPG">'
+            u'https://commons.wikimedia.org/wiki/File:Engl-Bürgerkrieg.JPG</a></p>'
+            u'<strong>Najbardziej użytecznym dla użytkowników przeszukujących stronę zestawem słów kluczowych '
+            u'opisujących ten obiekt będzie:</strong>'),
+        choices=[
+            (2, u'Anglia, wojna domowa, karykatura, propaganda,'),
+            (0, u'komiks, śmiech, Anglicy, Wielka Brytania, psy,'),
+            (1, u'Angielska Wojna Domowa 1642-1651, propaganda.')])
+    pyt18 = quiz_question(
+        label=u'18) Podczas wycieczki szkolnej zrobiłeś sporo zdjęć znajomym, w różnych sytuacjach. '
+              u'Masz również dostęp do wielu fotografii, które przygotowali twoi koledzy i koleżanki. '
+              u'Zamierzasz niektóre z nich zamieścić na swoim kanale w serwisie społecznościowym. Możesz opublikować:',
+        choices=[
+            (0, u'zdjęcia prezentujące selfie (o ile nie przedstawiają więcej niż dwóch osób), '
+                u'zdjęcia grupy podczas zwiedzania, zdjęcia, które ktoś zrobił tobie na tle zwiedzanych obiektów, '
+                u'zdjęcia, na których ludzie się uśmiechają i cieszą, że robisz im zdjęcie,'),
+            (1, u'zdjęcia prezentujące selfie (ale tylko twoje), zdjęcia pokazujące w oddali grupę na tle '
+                u'zwiedzanych obiektów, zdjęcia, zdjęcia na których widać tylko ciebie, na tle zwiedzanych obiektów,'),
+            (2, u'zdjęcia prezentujące selfie (na których jesteś ty, ale również inne osoby, które potwierdziły, '
+                u'że możesz opublikować fotografie), zdjęcia na których widać tylko ciebie '
+                u'i masz zgodę na ich publikację od osoby, która wykonała fotografię, '
+                u'wykonane przez ciebie zdjęcia zwiedzanych obiektów.')])
+    pyt19 = quiz_question(
+        label=u'19) Korzystając z sieci, natrafiamy na różne interesujące informacje. '
+              u'Pojawiają się w wielu serwisach informacyjnych, społecznościowych, w postaci reklam '
+              u'dołączanych do materiałów wideo, reklam zamieszczonych w tekstach itp. '
+              u'Na co warto zwracać uwagę, podczas codziennego korzystania z mediów, '
+              u'żeby efektywnie wykorzystać czas spędzony w internecie?',
+        choices=[
+            (1, u'zaplanować czas spędzany na korzystaniu z mediów i starać się trzymać swojego planu, '
+                u'nie unikasz jednak nagłych rozmów przez komunikator, oglądania postów, '
+                u'zdjęć i filmików dodawanych przez znajomych,'),
+            (0, u'zaplanować, co będziesz robił(a), ale traktujesz to jako ramę działania, wiesz, '
+                u'że po drodze pojawi się wiele interesujących informacji, z których skorzystasz,'),
+            (2, u'zaplanować czas spędzany na korzystaniu z mediów i rejestrować, co, '
+                u'kiedy i przez ile czasu robisz, np. instalując aplikację do mierzenia czasu spędzanego w sieci. '
+                u'Następnie analizujesz zebrane informacje i starasz się określić, co robisz zbyt często '
+                u'i jakie rzeczy odciągają Twoją uwagę od tych zaplanowanych.')])
+    pyt20 = quiz_question(
+        label=u'20) Blokująca reklamy wtyczka do przeglądarki działa w następujący sposób:',
+        choices=[
+            (0, u'analizuje treść tekstów oraz obrazków i blokuje te, które zawierają reklamy,'),
+            (1, u'blokuje wyświetlanie plików reklam zanim wyświetli je przeglądarka,'),
+            (2, u'blokuje komunikację przeglądarki z serwerami publikującymi reklamy.')])
+
+    ANSWER_COMMENTS = [
+        (u'dobrze', u'źle', u'najlepiej'),
+        (u'średnio', u'głupio', u'super'),
+        (u'słabo', u'beznadziejnie', u'ujdzie'),
+        (u'trója', u'pała', u'szóstka'),
+        (u'dobrze', u'źle', u'najlepiej'),
+        (u'średnio', u'głupio', u'super'),
+        (u'słabo', u'beznadziejnie', u'ujdzie'),
+        (u'trója', u'pała', u'szóstka'),
+        (u'dobrze', u'źle', u'najlepiej'),
+        (u'średnio', u'głupio', u'super'),
+        (u'słabo', u'beznadziejnie', u'ujdzie'),
+        (u'trója', u'pała', u'szóstka'),
+        (u'dobrze', u'źle', u'najlepiej'),
+        (u'średnio', u'głupio', u'super'),
+        (u'słabo', u'beznadziejnie', u'ujdzie'),
+        (u'trója', u'pała', u'szóstka'),
+        (u'dobrze', u'źle', u'najlepiej'),
+        (u'średnio', u'głupio', u'super'),
+        (u'słabo', u'beznadziejnie', u'ujdzie'),
+        (u'trója', u'pała', u'szóstka'),
+    ]
+
+    @classmethod
+    def results(cls, contact):
+        fields = cls().fields
+
+        def get_idx(choices, answer):
+            return dict((score, i) for i, (score, text) in enumerate(choices))[answer]
+
+        def question_data(i):
+            field = 'pyt%s' % i
+            choices = fields[field].choices
+            score = contact.body[field]
+            chosen_idx = get_idx(choices, score)
+            correct_idx = get_idx(choices, 2)
+            return {
+                'score': score,
+                'chosen_idx': chosen_idx,
+                'correct_idx': correct_idx,
+                'chosen': 'abc'[chosen_idx],
+                'correct': 'abc'[correct_idx],
+                'label': fields[field].label,
+                'comment': cls.ANSWER_COMMENTS[i-1][chosen_idx],
+                'answers': [(text, a_score == score, a_score == 2) for a_score, text in choices],
+            }
+        question_count = len(fields) - 1
+        questions = [question_data(i) for i in xrange(1, question_count + 1)]
+        points = sum(question['score'] for question in questions)
+        return {'questions': questions, 'points': points/2., 'total': question_count}
index ac11db0..0997331 100644 (file)
@@ -2,16 +2,18 @@
   padding: .3em;
   vertical-align: top;
   text-align: left; }
   padding: .3em;
   vertical-align: top;
   text-align: left; }
-.submit-form td ul {
+.submit-form ul {
   padding: 0;
   list-style: none;
   margin: 0; }
 .submit-form th {
   max-width: 16em;
   font-weight: normal; }
   padding: 0;
   list-style: none;
   margin: 0; }
 .submit-form th {
   max-width: 16em;
   font-weight: normal; }
-.submit-form .required th label:before {
+.submit-form .required label:before {
   content: "* ";
   color: red; }
   content: "* ";
   color: red; }
+.submit-form p.required {
+  font-weight: bold; }
 .submit-form .errorlist {
   padding: 0 0 0 1em;
   margin: 0;
 .submit-form .errorlist {
   padding: 0 0 0 1em;
   margin: 0;
index 8ef87de..ffe8c24 100755 (executable)
@@ -4,7 +4,7 @@
         vertical-align: top;
         text-align: left;
     }
         vertical-align: top;
         text-align: left;
     }
-    td ul {
+    ul {
         padding: 0;
         list-style: none;
         margin: 0;
         padding: 0;
         list-style: none;
         margin: 0;
         max-width: 16em;
         font-weight: normal;
     }
         max-width: 16em;
         font-weight: normal;
     }
-    .required th label:before {
+    .required label:before {
         content: "* ";
         color: red;
     }
         content: "* ";
         color: red;
     }
+    p.required {
+        font-weight: bold;
+    }
     .errorlist {
         padding: 0 0 0 1em;
         margin: 0;
     .errorlist {
         padding: 0 0 0 1em;
         margin: 0;
diff --git a/edumed/templates/contact/sciezki-kopernika-test/form.html b/edumed/templates/contact/sciezki-kopernika-test/form.html
new file mode 100644 (file)
index 0000000..50b93d9
--- /dev/null
@@ -0,0 +1,6 @@
+{% extends "contact/form.html" %}
+
+{% block form %}
+    {{ form.as_p }}
+    <p><button>{{ form.submit_label }}</button></p>
+{% endblock %}
diff --git a/edumed/templates/contact/sciezki-kopernika-test/mail_subject.txt b/edumed/templates/contact/sciezki-kopernika-test/mail_subject.txt
new file mode 100644 (file)
index 0000000..f315550
--- /dev/null
@@ -0,0 +1 @@
+Wyniki testu
\ No newline at end of file
diff --git a/edumed/templates/contact/sciezki-kopernika-test/results.html b/edumed/templates/contact/sciezki-kopernika-test/results.html
new file mode 100644 (file)
index 0000000..bb421eb
--- /dev/null
@@ -0,0 +1,28 @@
+{% extends base_template|default:"base.html" %}
+{% load i18n %}
+
+{% block title %}Wyniki{% endblock %}
+
+{% block body %}
+    <h1>Wyniki</h1>
+
+    <p>Suma uzyskanych punktów: {{ results.points|floatformat }} na {{ results.total }} możliwych.</p>
+
+    <p class="box-button" style="max-width: 20em;"><a href="{% url 'contact_form' 'sciezki-kopernika' %}" class="nice-button">Zgłoś się na warsztaty</a></p>
+
+    {% for question in results.questions %}
+        <strong>{{ question.label }}</strong>
+        <ol type="a">
+            {% for answer, chosen, correct in question.answers %}
+                <li style="{% if chosen %}font-weight: bold;{% endif %}{% if correct %}color: #00cc44;{% endif %}">{{ answer }}</li>
+            {% endfor %}
+        </ol>
+        {% if question.chosen == question.correct %}
+            <p>Wybrana poprawna odpowiedź {{ question.chosen }}.</p>
+        {% else %}
+            <p>Wybrana odpowiedź {{ question.chosen }}, poprawna odpowiedź {{ question.correct }}.</p>
+        {% endif %}
+        <p>Komentarz do odpowiedzi: {{ question.comment }}</p>
+    {% endfor %}
+    <p class="box-button" style="max-width: 20em;"><a href="{% url 'contact_form' 'sciezki-kopernika' %}" class="nice-button">Zgłoś się na warsztaty</a></p>
+{% endblock %}
\ No newline at end of file
diff --git a/edumed/templates/contact/sciezki-kopernika-test/results_email.txt b/edumed/templates/contact/sciezki-kopernika-test/results_email.txt
new file mode 100644 (file)
index 0000000..73e55d8
--- /dev/null
@@ -0,0 +1,18 @@
+Witaj,
+
+Oto wyniki testu:
+
+Suma uzyskanych punktów: {{ results.points|floatformat }} na {{ results.total }} możliwych.
+
+Zapraszamy do zgłoszenia się na warsztaty:
+https://edukacjamedialna.edu.pl{% url 'contact_form' 'sciezki-kopernika' %}
+
+Pod poniższym adresem możesz obejrzeć swoje odpowiedzi z komentarzami:
+https://edukacjamedialna.edu.pl{% url 'contact_results' contact.id contact.digest %}
+
+
+Z pozdrowieniami
+fundacja Nowoczesna Polska
+
+--
+Wiadomość wysłana automatycznie. Prosimy na nią nie odpowiadać.
\ No newline at end of file
diff --git a/edumed/templatetags/__init__.py b/edumed/templatetags/__init__.py
new file mode 100644 (file)
index 0000000..d384124
--- /dev/null
@@ -0,0 +1,4 @@
+# -*- 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.
+#
diff --git a/edumed/templatetags/inline_stylesheet.py b/edumed/templatetags/inline_stylesheet.py
new file mode 100644 (file)
index 0000000..76f0faf
--- /dev/null
@@ -0,0 +1,39 @@
+# -*- coding: utf-8 -*-
+# https://github.com/jazzband/django-pipeline/issues/295#issuecomment-152095865
+# adjusted for older pipeline
+from __future__ import unicode_literals
+import codecs
+
+from django.contrib.staticfiles.storage import staticfiles_storage
+from django.utils.safestring import mark_safe
+from django import template
+from pipeline.templatetags import compressed
+
+register = template.Library()
+
+
+class StylesheetNode(compressed.CompressedCSSNode):
+    def render_css(self, package, path):
+        return self.render_individual_css(package, [path])
+
+    def render_individual_css(self, package, paths, **kwargs):
+        html = []
+        for path in paths:
+            with codecs.open(staticfiles_storage.path(path), 'r', 'utf-8') as f:
+                html.append(f.read())
+        html = '<style type="text/css">' + '\n'.join(html) + '</style>'
+        return mark_safe(html)
+
+
+@register.tag
+def inline_stylesheet(parser, token):
+    """ Template tag that mimics pipeline's stylesheet tag, but embeds
+    the resulting CSS directly in the page.
+    """
+    try:
+        tag_name, name = token.split_contents()
+    except ValueError:
+        raise template.TemplateSyntaxError(
+            '%r requires exactly one argument: the name of a group in the PIPELINE_CSS setting'
+            % token.split_contents()[0])
+    return StylesheetNode(name)