From: Jan Szejko Date: Fri, 1 Sep 2017 08:57:17 +0000 (+0200) Subject: new olimpiada contact form (with student confirmations) X-Git-Url: https://git.mdrn.pl/edumed.git/commitdiff_plain/84e0a92d17b4a782dee2c4b257ee0e5f66be9af6 new olimpiada contact form (with student confirmations) --- diff --git a/contact/models.py b/contact/models.py index 1c92610..5f031c2 100644 --- a/contact/models.py +++ b/contact/models.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- -import yaml from django.db import models from django.utils.encoding import smart_unicode from django.utils.translation import ugettext_lazy as _ @@ -17,6 +16,7 @@ class Contact(models.Model): @staticmethod def pretty_print(value, for_html=False): if type(value) in (tuple, list, dict): + import yaml value = yaml.safe_dump(value, allow_unicode=True, default_flow_style=False) if for_html: value = smart_unicode(value).replace(u" ", unichr(160)) diff --git a/edumed/contact_forms.py b/edumed/contact_forms.py index 7e7faca..2cb7dd9 100644 --- a/edumed/contact_forms.py +++ b/edumed/contact_forms.py @@ -10,6 +10,7 @@ from django.core.validators import validate_email from django.template.loader import render_to_string from django.utils.translation import ugettext_lazy as _ +from wtem.models import Confirmation WOJEWODZTWA = ( u'dolnośląskie', @@ -227,7 +228,7 @@ class WTEMForm(ContactForm): except ValidationError: pass else: - send_mail(mail_subject, mail_body, 'edukacjamedialna@nowoczesnapolska.org.pl', [email], + send_mail(mail_subject, mail_body, 'olimpiada@nowoczesnapolska.org.pl', [email], fail_silently=True) return contact @@ -239,7 +240,7 @@ class CommissionForm(forms.Form): class OlimpiadaForm(ContactForm): - disabled = True + disabled = False disabled_template = 'wtem/disabled_contact_form.html' form_tag = "olimpiada" form_title = u"Olimpiada Cyfrowa - Elektroniczny System Zgłoszeń" @@ -254,6 +255,7 @@ class OlimpiadaForm(ContactForm): przewodniczacy = forms.CharField(label=u'Imię i nazwisko Przewodniczącego/Przewodniczącej', max_length=128) school = forms.CharField(label=u'Nazwa szkoły', max_length=255) school_address = forms.CharField(label=u'Adres szkoły', widget=forms.Textarea, max_length=1000) + school_wojewodztwo = forms.ChoiceField(label=u'Województwo', choices=WOJEWODZTWO_CHOICES) school_email = forms.EmailField(label=u'Adres e-mail szkoły', max_length=128) school_phone = forms.CharField(label=u'Numer telefonu szkoły', max_length=32) school_www = forms.URLField(label=u'Strona WWW szkoły', max_length=255, required=False) @@ -307,17 +309,25 @@ class OlimpiadaForm(ContactForm): contact = super(OlimpiadaForm, self).save(request, formsets) mail_subject = render_to_string('contact/olimpiada/student_mail_subject.html').strip() - mail_body = render_to_string('contact/olimpiada/student_mail_body.html') for formset in formsets or []: if formset.prefix == 'student': for f in formset.forms: email = f.cleaned_data.get('email', None) + try: + confirmation = Confirmation.objects.get(email=email) + except Confirmation.DoesNotExist: + first_name = f.cleaned_data.get('first_name', None) + last_name = f.cleaned_data.get('last_name', None) + confirmation = Confirmation.create( + first_name=first_name, last_name=last_name, email=email, contact=contact) + mail_body = render_to_string( + 'contact/olimpiada/student_mail_body.html', {'confirmation': confirmation}) try: validate_email(email) except ValidationError: pass else: - send_mail(mail_subject, mail_body, 'edukacjamedialna@nowoczesnapolska.org.pl', [email], + send_mail(mail_subject, mail_body, 'olimpiada@nowoczesnapolska.org.pl', [email], fail_silently=True) return contact diff --git a/edumed/templates/contact/olimpiada/form.html b/edumed/templates/contact/olimpiada/form.html index c28925a..3a4f5be 100755 --- a/edumed/templates/contact/olimpiada/form.html +++ b/edumed/templates/contact/olimpiada/form.html @@ -22,7 +22,7 @@
{% csrf_token %} {% render_honeypot_field %} -

Dane Przewodniczącego i szkoły zgłaszającej Uczestników:

+

Dane Przewodniczącego Komisji Szkolnej i szkoły zgłaszającej Uczestników:

{{ form.as_table }}
diff --git a/edumed/templates/contact/olimpiada/mail_body.txt b/edumed/templates/contact/olimpiada/mail_body.txt index 0a63f92..3505dca 100755 --- a/edumed/templates/contact/olimpiada/mail_body.txt +++ b/edumed/templates/contact/olimpiada/mail_body.txt @@ -1,6 +1,7 @@ -Dziękujemy za rejestrację w Olimpiadzie Cyfrowej. -Do udziału zostały zgłoszone następujące osoby: -{% for student in contact.body.student %}* {{ student.first_name }} {{ student.last_name }}{% endfor %} +Dziękujemy za rejestrację Komisji Szkolnej do Olimpiady Cyfrowej. +Do udziału w Olimpiadzie zostały zgłoszone następujące osoby: +{% for student in contact.body.student %}* {{ student.first_name }} {{ student.last_name }} +{% endfor %} Każdy zgłoszony uczeń powinien otrzymać wiadomość z potwierdzeniem rejestracji. Prosimy upewnić się, czy potwierdzenie dotarło do każdego @@ -8,12 +9,12 @@ ze zgłoszonych uczniów. W ten sposób zweryfikujemy, czy podane adresy są prawidłowe. Pierwszy etap Olimpiady (test on-line) odbędzie się -15 listopada 2016 r. o godz. 10:00 i potrwa 90 minut. +23 listopada 2017 r. godz. 10:00 i potrwa 90 minut. -Wszystkie ogłoszenia związane z Turniejem będą publikowane na stronie https://olimpiadacyfrowa.pl. +Wszystkie ogłoszenia związane z Olimpiadą będą publikowane na stronie https://olimpiadacyfrowa.pl. W razie pytań lub wątpliwości można kontaktować się z nami, pisząc na adres: olimpiada@nowoczesnapolska.org.pl. -Z pozdrowieniami, +Pozdrawiamy, Zespół Olimpiady Cyfrowej Fundacja Nowoczesna Polska \ No newline at end of file diff --git a/edumed/templates/contact/olimpiada/student_mail_body.html b/edumed/templates/contact/olimpiada/student_mail_body.html index eb3df3e..bcc32c9 100644 --- a/edumed/templates/contact/olimpiada/student_mail_body.html +++ b/edumed/templates/contact/olimpiada/student_mail_body.html @@ -1,17 +1,19 @@ -Witaj, +Dzień dobry, Przewodniczący Komisji Szkolnej właśnie zgłosił Cię do Olimpiady Cyfrowej. Cieszymy się, że chcesz wziąć w niej udział. -Pierwszy etap Olimpiady (test on-line) odbędzie się 15 listopada 2016 r. -o godz. 10:00 i potrwa 90 minut. +Prosimy o potwierdzenie udziału przez kliknięcie w poniższy link: +https://olimpiadacyfrowa.pl{{ confirmation.absolute_url }} + +Pierwszy etap Olimpiady (test on-line) odbędzie się 23 listopada 2017 r. o godz. 10:00 i potrwa 90 minut. Szczegółowe informacje na temat pierwszego etapu Olimpiady oraz wszystkie ogłoszenia z nią związane będą publikowane na stronie https://olimpiadacyfrowa.pl. W razie pytań lub wątpliwości możesz kontaktować się z nami, pisząc na adres olimpiada@nowoczesnapolska.org.pl. -Z pozdrowieniami, +Pozdrawiamy, Zespół Olimpiady Cyfrowej -Fundacja Nowoczesna Polska +Fundacja Nowoczesna Polska \ No newline at end of file diff --git a/edumed/templates/contact/olimpiada/thanks.html b/edumed/templates/contact/olimpiada/thanks.html index f05dd36..1e314d1 100755 --- a/edumed/templates/contact/olimpiada/thanks.html +++ b/edumed/templates/contact/olimpiada/thanks.html @@ -1,7 +1,7 @@ {% extends "contact/thanks.html" %} {% block contact_form_description %} -

Dziękujemy za rejestrację w Olimpiadzie Cyfrowej.

+

Dziękujemy za rejestrację Komisji Szkolnej do Olimpiady Cyfrowej.

Na adres e-mail Przewodniczącego/Przewodniczącej została wysłana wiadomość potwierdzająca rejestrację.

diff --git a/wtem/migrations/0010_auto__add_confirmation.py b/wtem/migrations/0010_auto__add_confirmation.py new file mode 100644 index 0000000..63f9d60 --- /dev/null +++ b/wtem/migrations/0010_auto__add_confirmation.py @@ -0,0 +1,115 @@ +# -*- coding: utf-8 -*- +from south.utils import datetime_utils as 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 'Confirmation' + db.create_table(u'wtem_confirmation', ( + (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('first_name', self.gf('django.db.models.fields.CharField')(max_length=100)), + ('last_name', self.gf('django.db.models.fields.CharField')(max_length=100)), + ('email', self.gf('django.db.models.fields.EmailField')(unique=True, max_length=100)), + ('contact', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['contact.Contact'], null=True)), + ('key', self.gf('django.db.models.fields.CharField')(max_length=30)), + ('confirmed', self.gf('django.db.models.fields.BooleanField')(default=False)), + )) + db.send_create_signal(u'wtem', ['Confirmation']) + + + def backwards(self, orm): + # Deleting model 'Confirmation' + db.delete_table(u'wtem_confirmation') + + + models = { + u'auth.group': { + 'Meta': {'object_name': 'Group'}, + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + u'auth.permission': { + 'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + u'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Group']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Permission']"}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + u'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'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'ip': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}) + }, + u'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + u'wtem.assignment': { + 'Meta': {'object_name': 'Assignment'}, + 'exercises': ('jsonfield.fields.JSONField', [], {}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']", 'unique': 'True'}) + }, + u'wtem.attachment': { + 'Meta': {'object_name': 'Attachment'}, + 'exercise_id': ('django.db.models.fields.IntegerField', [], {}), + 'file': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'submission': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['wtem.Submission']"}), + 'tag': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True', 'blank': 'True'}) + }, + u'wtem.confirmation': { + 'Meta': {'object_name': 'Confirmation'}, + 'confirmed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'contact': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contact.Contact']", 'null': 'True'}), + 'email': ('django.db.models.fields.EmailField', [], {'unique': 'True', 'max_length': '100'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'key': ('django.db.models.fields.CharField', [], {'max_length': '30'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + u'wtem.submission': { + 'Meta': {'object_name': 'Submission'}, + 'answers': ('django.db.models.fields.CharField', [], {'max_length': '65536', 'null': 'True', 'blank': 'True'}), + 'contact': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contact.Contact']", 'null': 'True'}), + 'email': ('django.db.models.fields.EmailField', [], {'unique': 'True', 'max_length': '100'}), + 'end_time': ('django.db.models.fields.CharField', [], {'max_length': '5', 'null': 'True', 'blank': 'True'}), + 'examiners': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': u"orm['auth.User']", 'null': 'True', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}), + 'key_sent': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'marks': ('jsonfield.fields.JSONField', [], {'default': '{}'}) + } + } + + complete_apps = ['wtem'] \ No newline at end of file diff --git a/wtem/models.py b/wtem/models.py index 3947632..69337a0 100644 --- a/wtem/models.py +++ b/wtem/models.py @@ -7,6 +7,7 @@ import json from django.db import models from django.contrib.auth.models import User from django.core.exceptions import ValidationError +from django.core.urlresolvers import reverse from django.utils.translation import ugettext as _ from jsonfield import JSONField @@ -19,6 +20,12 @@ f.close() DEBUG_KEY = 'smerfetka159' +def make_key(length): + return ''.join( + random.choice(string.ascii_uppercase + string.ascii_lowercase + string.digits) + for i in range(length)) + + class Submission(models.Model): contact = models.ForeignKey(Contact, null=True) key = models.CharField(max_length=30, unique=True) @@ -38,8 +45,7 @@ class Submission(models.Model): def generate_key(cls): key = '' while not key or key in [record['key'] for record in cls.objects.values('key')]: - key = ''.join(random.choice(string.ascii_uppercase + string.ascii_lowercase + string.digits) - for i in range(30)) + key = make_key(30) return key @classmethod @@ -177,5 +183,30 @@ class Assignment(models.Model): return self.user.username + ': ' + ','.join(map(str, self.exercises)) +class Confirmation(models.Model): + first_name = models.CharField(max_length=100) + last_name = models.CharField(max_length=100) + email = models.EmailField(max_length=100, unique=True) + contact = models.ForeignKey(Contact, null=True) + key = models.CharField(max_length=30) + confirmed = models.BooleanField(default=False) + + @classmethod + def create(cls, first_name, last_name, email, contact=None, key=None): + confirmation = cls( + contact=contact, + key=key if key else make_key(30), + first_name=first_name, + last_name=last_name, + email=email + ) + + confirmation.save() + return confirmation + + def absolute_url(self): + return reverse('student_confirmation', args=(self.id, self.key)) + + def exercise_checked_manually(exercise): return (exercise['type'] in ('open', 'file_upload')) or 'open_part' in exercise diff --git a/wtem/templates/wtem/confirmed.html b/wtem/templates/wtem/confirmed.html new file mode 100644 index 0000000..d08f9e9 --- /dev/null +++ b/wtem/templates/wtem/confirmed.html @@ -0,0 +1,13 @@ +{% extends 'base_super.html' %} + +{% block body %} +

{% include "wtem/title.html" %}

+

Potwierdzono udział

+ + {% if was_confirmed %} +

Udział w Olimpiadzie Cyfrowej został już wcześniej potwierdzony.

+ {% else %} +

Dziękujemy za potwierdzenie udziału w Olimpiadzie Cyfrowej!

+ {% endif %} + +{% endblock %} \ No newline at end of file diff --git a/wtem/urls.py b/wtem/urls.py index 3e96c2e..58f39e3 100644 --- a/wtem/urls.py +++ b/wtem/urls.py @@ -1,9 +1,10 @@ # -*- coding: utf-8 -*- from django.conf.urls import patterns, url -from .views import form, form_during +from . import views urlpatterns = patterns( '', - url(r'^_test/(?P.*)/$', form_during), - url(r'^(?P.*)/$', form, name='wtem_form') + url(r'^potwierdzenie/(?P.*)/(?P.*)/$', views.confirmation, name='student_confirmation'), + url(r'^_test/(?P.*)/$', views.form_during), + url(r'^(?P.*)/$', views.form, name='wtem_form'), ) diff --git a/wtem/views.py b/wtem/views.py index 0696174..b5f7548 100644 --- a/wtem/views.py +++ b/wtem/views.py @@ -4,10 +4,11 @@ from copy import deepcopy from django.conf import settings from django.http import HttpResponseForbidden -from django.shortcuts import render +from django.shortcuts import render, get_object_or_404 from django.views.decorators.cache import never_cache from django.views.decorators.csrf import csrf_exempt +from wtem.models import Confirmation from .forms import WTEMForm from .models import Submission, DEBUG_KEY, exercises @@ -68,3 +69,12 @@ def form_during(request, key): return render(request, 'wtem/thanks.html', dict(end_time=submission.end_time)) else: raise Exception + + +def confirmation(request, id, key): + conf = get_object_or_404(Confirmation, id=id, key=key) + was_confirmed = conf.confirmed + if not was_confirmed: + conf.confirmed = True + conf.save() + return render(request, 'wtem/confirmed.html', {'confirmation': conf, 'was_confirmed': was_confirmed})