diff --git a/requirements.txt b/requirements.txt index a4015bf9..777295e8 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,7 @@ coverage==4.3.4 -Django==1.10.5 -django-debug-toolbar==1.6 +Django==1.10.6 +django-debug-toolbar==1.7 docutils==0.13.1 -sqlparse==0.2.2 +sqlparse==0.2.3 freezegun==0.3.8 django-formtools==2.0 diff --git a/src/feedback/forms.py b/src/feedback/forms.py index ee9cb8f0..bbe9db49 100644 --- a/src/feedback/forms.py +++ b/src/feedback/forms.py @@ -165,6 +165,16 @@ class Meta: fields = ('anschrift', 'fachgebiet') +CLOSE_ORDER_CHOICES = ( + ('ja', 'Ja'), + ('nein', 'Nein') +) + + +class CloseOrderForm(forms.Form): + auswahl = forms.ChoiceField(choices=CLOSE_ORDER_CHOICES) + + class CreateBarcodeScannEventForm(forms.ModelForm): """Handelt die erste haelfte von Barcode scanns""" scanner_token = forms.CharField() diff --git a/src/feedback/migrations/0035_auto_20170313_1743.py b/src/feedback/migrations/0035_auto_20170313_1743.py new file mode 100644 index 00000000..8ef254d6 --- /dev/null +++ b/src/feedback/migrations/0035_auto_20170313_1743.py @@ -0,0 +1,30 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.6 on 2017-03-13 17:43 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('feedback', '0034_auto_20170207_1854'), + ] + + operations = [ + migrations.AlterField( + model_name='barcodeallowedstate', + name='allow_state', + field=models.IntegerField(choices=[(100, 'Angelegt'), (200, 'Bestellung ge\xf6ffnet'), (300, 'Keine Evaluation'), (310, 'Keine Evaluation final'), (500, 'Bestellung liegt vor'), (510, 'Bestellung wird verarbeitet'), (600, 'Gedruckt'), (700, 'Versandt'), (800, 'B\xf6gen eingegangen'), (900, 'B\xf6gen gescannt'), (1000, 'Ergebnisse versandt')], null=True, unique=True), + ), + migrations.AlterField( + model_name='log', + name='status', + field=models.IntegerField(choices=[(100, 'Angelegt'), (200, 'Bestellung ge\xf6ffnet'), (300, 'Keine Evaluation'), (310, 'Keine Evaluation final'), (500, 'Bestellung liegt vor'), (510, 'Bestellung wird verarbeitet'), (600, 'Gedruckt'), (700, 'Versandt'), (800, 'B\xf6gen eingegangen'), (900, 'B\xf6gen gescannt'), (1000, 'Ergebnisse versandt')], default=100), + ), + migrations.AlterField( + model_name='veranstaltung', + name='status', + field=models.IntegerField(choices=[(100, 'Angelegt'), (200, 'Bestellung ge\xf6ffnet'), (300, 'Keine Evaluation'), (310, 'Keine Evaluation final'), (500, 'Bestellung liegt vor'), (510, 'Bestellung wird verarbeitet'), (600, 'Gedruckt'), (700, 'Versandt'), (800, 'B\xf6gen eingegangen'), (900, 'B\xf6gen gescannt'), (1000, 'Ergebnisse versandt')], default=100), + ), + ] diff --git a/src/feedback/models/base.py b/src/feedback/models/base.py index f8f62d39..3ed2ef5b 100644 --- a/src/feedback/models/base.py +++ b/src/feedback/models/base.py @@ -318,7 +318,9 @@ class Veranstaltung(models.Model): STATUS_ANGELEGT = 100 STATUS_BESTELLUNG_GEOEFFNET = 200 STATUS_KEINE_EVALUATION = 300 + STATUS_KEINE_EVALUATION_FINAL = 310 STATUS_BESTELLUNG_LIEGT_VOR = 500 + STATUS_BESTELLUNG_WIRD_VERARBEITET = 510 STATUS_GEDRUCKT = 600 STATUS_VERSANDT = 700 STATUS_BOEGEN_EINGEGANGEN = 800 @@ -329,7 +331,9 @@ class Veranstaltung(models.Model): (STATUS_ANGELEGT, 'Angelegt'), (STATUS_BESTELLUNG_GEOEFFNET, 'Bestellung geöffnet'), (STATUS_KEINE_EVALUATION, 'Keine Evaluation'), + (STATUS_KEINE_EVALUATION_FINAL, 'Keine Evaluation final'), (STATUS_BESTELLUNG_LIEGT_VOR, 'Bestellung liegt vor'), + (STATUS_BESTELLUNG_WIRD_VERARBEITET, 'Bestellung wird verarbeitet'), (STATUS_GEDRUCKT, 'Gedruckt'), (STATUS_VERSANDT, 'Versandt'), (STATUS_BOEGEN_EINGEGANGEN, 'Bögen eingegangen'), diff --git a/src/feedback/tests/test_views_intern.py b/src/feedback/tests/test_views_intern.py index bf79f0d5..f6e78858 100644 --- a/src/feedback/tests/test_views_intern.py +++ b/src/feedback/tests/test_views_intern.py @@ -1,434 +1,494 @@ -# coding=utf-8 - -import os - -from StringIO import StringIO - -from django.conf import settings -from django.core import mail -from django.test import TestCase -from django.core.urlresolvers import reverse - -from feedback.forms import UploadFileForm -from feedback.models import Semester, Person, Veranstaltung, Fragebogen2009, Mailvorlage, Einstellung, \ - Fachgebiet, FachgebietEmail -from feedback.tests.tools import NonSuTestMixin, get_veranstaltung - -from feedback import tests - - -class InternMiscTest(NonSuTestMixin, TestCase): - def test_index(self): - path = tests.INDEX_END - self.do_non_su_test(path) - self.client.login(username='supers', password='pw') - - s = Semester.objects.create(semester=20110, fragebogen='2009', sichtbarkeit='ADM') - - response = self.client.get(path, **{'REMOTE_USER': 'super'}) - self.assertEqual(response.templates[0].name, 'intern/index.html') - self.assertEqual(response.context['cur_semester'], s) - - def test_fragebogensprache(self): - path = '/intern/fragebogensprache/' - self.do_non_su_test(path) - self.client.login(username='supers', password='pw') - - Semester.objects.create(semester=20110, fragebogen='2009', sichtbarkeit='ADM') - - response = self.client.get(path, **{'REMOTE_USER': 'super'}) - self.assertEqual(response.templates[0].name, 'intern/fragebogensprache.html') - - def test_export_veranstaltungen_get(self): - path = '/intern/export_veranstaltungen/' - self.do_non_su_test(path) - self.client.login(username='supers', password='pw') - - response = self.client.get(path, **{'REMOTE_USER': 'super'}) - self.assertEqual(response.templates[0].name, 'intern/export_veranstaltungen.html') - self.assertSequenceEqual(response.context['semester'], list(Semester.objects.all())) - - -class ExportVeranstaltungenTest(NonSuTestMixin, TestCase): - def test_export_veranstaltungen_post(self): - path = '/intern/export_veranstaltungen/' - self.client.login(username='supers', password='pw') - self.client.login(username='supers', password='pw') - - _, v1 = get_veranstaltung('v') - s, v2 = get_veranstaltung('vu') - empty_semester = Semester.objects.create(semester=20120, fragebogen='2009', sichtbarkeit='ADM') - - p = Person.objects.create(vorname='Je', nachname='Mand', email='je@ma.nd', geschlecht='w') - v1.veranstalter.add(p) - v2.veranstalter.add(p) - - v1.grundstudium = True - v1.sprache = 'en' - v1.verantwortlich = p - v1.save() - - # kein Semester angegeben - response = self.client.post(path, **{'REMOTE_USER': 'super'}) - self.assertEqual(response.status_code, 302) - self.assertTrue(response['Location'].endswith('/intern/export_veranstaltungen/')) - - # keine Bestellung vorhanden - response = self.client.post(path, {'semester': s.semester}, **{'REMOTE_USER': 'super'}) - self.assertEqual(response.status_code, 302) - self.assertTrue(response['Location'].endswith('/intern/export_veranstaltungen/')) - - # niemand als Verantwortlicher eingetragen - v1.anzahl = 42 - v1.save() - v2.anzahl = 23 - v2.save() - response = self.client.post(path, {'semester': s.semester}, **{'REMOTE_USER': 'super'}) - self.assertEqual(response.status_code, 302) - self.assertTrue(response['Location'].endswith('/intern/export_veranstaltungen/')) - - response = self.client.post(path, {'semester': empty_semester.semester, 'xml_ubung': True}, **{'REMOTE_USER': 'super'}) - self.assertEqual(response.status_code, 302) - self.assertTrue(response['Location'].endswith('/intern/export_veranstaltungen/')) - - # keine Sprache angegeben - v2.verantwortlich = p - v2.save() - response = self.client.post(path, {'semester': s.semester}, **{'REMOTE_USER': 'super'}) - self.assertEqual(response.status_code, 302) - self.assertTrue(response['Location'].endswith('/intern/export_veranstaltungen/')) - - # alles OK - v2.sprache = 'de' - v2.save() - response = self.client.post(path, {'semester': s.semester}, **{'REMOTE_USER': 'super'}) - self.assertRegexpMatches(response['Content-Disposition'], - r'^attachment; filename="[a-zA-Z0-9_-]+\.xml"$') - - self.assertXMLEqual(response.content, - ''' - - - - - -Stoning I -FB 20 -123v-SS11 -SS11 -Vorlesung -42 -Informatik - - - -lv-1 - - -FB20Vv1e -SS11 -coversheet -0 - - - - - -Stoning I -FB 20 -123vu-SS11 -SS11 -Vorlesung + Übung -23 -Informatik - - - -lv-2 - - -FB20Vv1 -SS11 -coversheet -0 - - -''') - response = self.client.post(path, {'semester': s.semester, 'xml_ubung': True}, **{'REMOTE_USER': 'super'}) - self.assertRegexpMatches(response['Content-Disposition'], - r'^attachment; filename="[a-zA-Z0-9_-]+\.xml"$') - - self.assertXMLEqual(response.content, ''' - - - - - -Stoning I -FB 20 -123vu-SS11 -SS11 -Vorlesung + Übung -23 -Informatik - - - -lv-2 - - -FB20\xc3\x9cv1 -SS11 -coversheet -0 - - -''') - - def test_export_veranstaltungen_post_primaerdozent(self): - path = '/intern/export_veranstaltungen/' - self.client.login(username='supers', password='pw') - - s, v = get_veranstaltung('v') - p1 = Person.objects.create(vorname='Je', nachname='Mand', email='je@ma.nd', geschlecht='w') - p2 = Person.objects.create(vorname='Prim', nachname='Ardozent', email='prim@ardoz.ent', geschlecht='m') - p3 = Person.objects.create(vorname='Je1', nachname='Mand1', email='je1@ma.nd', geschlecht='m') - - v.veranstalter.add(p1) - v.veranstalter.add(p2) - v.veranstalter.add(p3) - v.ergebnis_empfaenger.add(p1) - v.ergebnis_empfaenger.add(p2) - v.ergebnis_empfaenger.add(p3) - - v.grundstudium = True - v.sprache = 'en' - v.verantwortlich = p1 - v.primaerdozent = p2 - v.anzahl = 42 - v.save() - - response = self.client.post(path, {'semester': s.semester}, **{'REMOTE_USER': 'super'}) - self.assertRegexpMatches(response['Content-Disposition'], - r'^attachment; filename="[a-zA-Z0-9_-]+\.xml"$') - - self.assertXMLEqual(response.content, - ''' - - - - - - - - - - - - - -Stoning I -FB 20 -123v-SS11 -SS11 -Vorlesung -42 -Informatik - - - -lv-1 - - -FB20Vv1e -SS11 -coversheet -0 - - -Je -Mand -je@ma.nd -f -pe-1 - -Prim -Ardozent -prim@ardoz.ent -m -pe-2 - -Je1 -Mand1 -je1@ma.nd -m -pe-3 - - -''') - - -# -class ImportErgebnisseTest(NonSuTestMixin, TestCase): - def setUp(self): - super(ImportErgebnisseTest, self).setUp() - self.path = '/intern/import_ergebnisse/' - self.s = Semester.objects.create(semester=20110, fragebogen='2009', sichtbarkeit='ADM') - - def test_get(self): - self.do_non_su_test(self.path) - self.client.login(username='supers', password='pw') - - response = self.client.get(self.path, **{'REMOTE_USER': 'super'}) - self.assertEqual(response.templates[0].name, 'intern/import_ergebnisse.html') - self.assertSequenceEqual(response.context['semester'], [self.s]) - self.assertTrue(isinstance(response.context['form'], UploadFileForm)) - - def test_post(self): - self.client.login(username='supers', password='pw') - default_params = {'semester': self.s, 'grundstudium': False, 'evaluieren': True} - Veranstaltung.objects.create(name='Test I', lv_nr='1', **default_params) - - # kein Semester angegeben - response = self.client.post(self.path, **{'REMOTE_USER': 'super'}) - self.assertEqual(response.status_code, 302) - self.assertTrue(response['Location'].endswith('/intern/import_ergebnisse/')) - - # unvollständiges Formular - response = self.client.post(self.path, {'semester': self.s.semester, 'file': ''}, **{'REMOTE_USER': 'super'}) - self.assertEqual(response.templates[0].name, 'intern/import_ergebnisse.html') - - # fehlerhafte Datei angegeben - f = StringIO('b;l;a;b;l;a;b;l;a') - f.name = 'test.csv' - response = self.client.post(self.path, {'semester': self.s.semester, 'file': f}, **{'REMOTE_USER': 'super'}) - f.close() - self.assertEqual(response.status_code, 302) - self.assertTrue(response['Location'].endswith('/intern/sync_ergebnisse/')) - - # alles OK - with open(settings.TESTDATA_PATH + 'ergebnis_test_20115.csv', 'r') as f: - response = self.client.post(self.path, {'semester': self.s.semester, 'file': f}, **{'REMOTE_USER': 'super'}) - self.assertEqual(response.status_code, 302) - self.assertTrue(response['Location'].endswith('/intern/sync_ergebnisse/')) - - -class SyncErgebnisseTest(NonSuTestMixin, TestCase): - def setUp(self): - super(SyncErgebnisseTest, self).setUp() - self.path = '/intern/sync_ergebnisse/' - self.s, self.v = get_veranstaltung('v') - - def test_get(self): - self.do_non_su_test(self.path) - self.client.login(username='supers', password='pw') - - response = self.client.get(self.path, **{'REMOTE_USER': 'super'}) - self.assertEqual(response.templates[0].name, 'intern/sync_ergebnisse.html') - self.assertSequenceEqual(response.context['semester'], [self.s]) - - def test_post(self): - self.client.login(username='supers', password='pw') - - # kein Semester angegeben - response = self.client.post(self.path, **{'REMOTE_USER': 'super'}) - self.assertEqual(response.status_code, 302) - self.assertTrue(response['Location'].endswith('/intern/sync_ergebnisse/')) - - # keine Ergebnisse gefunden - response = self.client.post(self.path, {'semester': self.s.semester}, **{'REMOTE_USER': 'super'}) - self.assertEqual(response.status_code, 302) - self.assertTrue(response['Location'].endswith('/intern/sync_ergebnisse/')) - - # alles OK - Fragebogen2009.objects.create(veranstaltung=self.v, ue_gesamt=1, - ue_e=2, ue_f=3, - ue_a=4, ue_b=5, ue_c=1, ue_d=2, - ue_g=3, ue_i=4, ue_j=5, ue_k=1) - response = self.client.post(self.path, {'semester': self.s.semester}, **{'REMOTE_USER': 'super'}) - self.assertEqual(response.status_code, 302) - self.assertTrue(response['Location'].endswith('/intern/sync_ergebnisse/')) - - -class SendmailTest(NonSuTestMixin, TestCase): - path = '/intern/sendmail/' - - def test_get(self): - self.do_non_su_test(self.path) - self.client.login(username='supers', password='pw') - - response = self.client.get(self.path, **{'REMOTE_USER': 'super'}) - self.assertEqual(response.templates[0].name, 'intern/sendmail.html') - - def test_post(self): - self.client.login(username='supers', password='pw') - get_veranstaltung('v') - s, v1 = get_veranstaltung('vu') - v1.anzahl = 42 - v1.sprache = 'de' - v1.save() - fb = Fachgebiet.objects.create(name="Fachgebiet1", kuerzel="FB1") - FachgebietEmail.objects.create(fachgebiet=fb, email_suffix="ul.bla", email_sekretaerin="sek@ul.bla") - p1 = Person.objects.create(vorname='Pe', nachname='Ter', email='pe@ter.bla') - p2 = Person.objects.create(vorname='Pa', nachname='Ul', email='pa@ul.bla', fachgebiet=fb) - - v1.veranstalter.add(p1) - v1.veranstalter.add(p2) - mv = Mailvorlage.objects.create(subject='Testmail', body='Dies ist eine Testmail.') - Einstellung.objects.create(name='bestellung_erlaubt', wert='0') - - params = {'uebernehmen': 'x', 'recipient': 'cur_sem_missing_order', 'subject': 'abc', 'body': 'xyz'} - - # kein Semester angegeben - response = self.client.post(self.path, params, **{'REMOTE_USER': 'super'}) - self.assertEqual(response.status_code, 302) - self.assertTrue(response['Location'].endswith('/intern/sendmail/')) - - # Vorlage übernehmen; Vorlage nicht angegeben - params['semester'] = s.semester - response = self.client.post(self.path, params, **{'REMOTE_USER': 'super'}) - self.assertEqual(response.status_code, 302) - self.assertTrue(response['Location'].endswith('/intern/sendmail/')) - - # Vorlage übernehmen; Vorlage ist angegeben - params['vorlage'] = mv.id - response = self.client.post(self.path, params, **{'REMOTE_USER': 'super'}) - self.assertEqual(response.templates[0].name, 'intern/sendmail.html') - self.assertEqual(response.context['subject'], mv.subject) - self.assertEqual(response.context['body'], mv.body) - - # Vorschau; Empfänger ist auf Veranstalter mit fehlenden Bestellungen eingestellt - del params['uebernehmen'] - params['vorschau'] = 'x' - response = self.client.post(self.path, params, **{'REMOTE_USER': 'super'}) - self.assertIn('intern/sendmail_preview.html', (t.name for t in response.templates)) - self.assertTrue(response.context['vorschau']) - - # Vorschau; Empfänger ist auf Veranstaltungen mit Ergebnissen eingestellt - params['recipient'] = 'cur_sem_results' - response = self.client.post(self.path, params, **{'REMOTE_USER': 'super'}) - self.assertIn('intern/sendmail_preview.html', (t.name for t in response.templates)) - self.assertTrue(response.context['vorschau']) - - # Vorschau: Check if the replacements are highlighted - color_span = '{}' - self.assertEqual(color_span.format('Grundlagen der Agrarphilosophie I') , response.context['veranstaltung']) - link_veranstalter = 'https://www.fachschaft.informatik.tu-darmstadt.de%s' % reverse('veranstalter-login') - link_suffix_format = '?vid=%d&token=%s' - self.assertEqual(color_span.format(link_veranstalter + (link_suffix_format % (1337, '0123456789abcdef'))) , response.context['link_veranstalter']) - - # Senden - del params['vorschau'] - params['senden'] = 'x' - params['recipient'] = 'cur_sem_all' - del params['vorlage'] - response = self.client.post(self.path, params, **{'REMOTE_USER': 'super'}) - self.assertEqual(response.status_code, 302) - self.assertTrue(response['Location'], tests.LOGIN_URL) - # Hier wird in Eclipse ein Fehler angezeigt; mail.outbox gibt es während der Testläufe - # aber wirklich (siehe https://docs.djangoproject.com/en/1.4/topics/testing/#email-services) - self.assertEqual(len(mail.outbox), 2) - self.assertEqual(len(mail.outbox[0].to), 3) # an zwei veranstalter und sekretaerin +# coding=utf-8 + +from StringIO import StringIO + +from django.conf import settings +from django.core import mail +from django.test import TestCase +from django.core.urlresolvers import reverse + +from feedback.forms import UploadFileForm +from feedback.models import Semester, Person, Veranstaltung, Fragebogen2009, Mailvorlage, Einstellung, \ + Fachgebiet, FachgebietEmail +from feedback.tests.tools import NonSuTestMixin, get_veranstaltung + +from feedback import tests + + +class CloseOrderTest(NonSuTestMixin, TestCase): + def setUp(self): + self.client.login(username='supers', password='pw') + self.s, self.v = get_veranstaltung('vu') + + def test_close_order_bestellung_liegt_vor_post(self): + path = '/intern/status_final/' + self.v.status = Veranstaltung.STATUS_BESTELLUNG_LIEGT_VOR + self.v.save() + + response = self.client.post(path, {'auswahl': 'ja', 'submit': 'Bestätigen'}, **{'REMOTE_USER': 'super'}) + + self.v.refresh_from_db() + self.assertEqual(response.status_code, 302) + self.assertEqual(self.v.status, Veranstaltung.STATUS_BESTELLUNG_WIRD_VERARBEITET) + + def test_close_order_keine_evaluation_post(self): + path = '/intern/status_final/' + self.v.status = Veranstaltung.STATUS_KEINE_EVALUATION + self.v.save() + + response = self.client.post(path, {'auswahl': 'ja', 'submit': 'Bestätigen'}, **{'REMOTE_USER': 'super'}) + + self.v.refresh_from_db() + self.assertEqual(response.status_code, 302) + self.assertEqual(self.v.status, Veranstaltung.STATUS_KEINE_EVALUATION_FINAL) + + def test_close_order_status_angelegt_post(self): + path = '/intern/status_final/' + self.v.status = Veranstaltung.STATUS_ANGELEGT + self.v.save() + + response = self.client.post(path, {'auswahl': 'ja', 'submit': 'Bestätigen'}, **{'REMOTE_USER': 'super'}) + + self.v.refresh_from_db() + self.assertEqual(response.status_code, 302) + self.assertEqual(self.v.status, Veranstaltung.STATUS_KEINE_EVALUATION_FINAL) + + def test_close_order_bestellung_geoeffnet_post(self): + path = '/intern/status_final/' + self.v.status = Veranstaltung.STATUS_BESTELLUNG_GEOEFFNET + self.v.save() + + response = self.client.post(path, {'auswahl': 'ja', 'submit': 'Bestätigen'}, **{'REMOTE_USER': 'super'}) + + self.v.refresh_from_db() + self.assertEqual(response.status_code, 302) + self.assertEqual(self.v.status, Veranstaltung.STATUS_KEINE_EVALUATION_FINAL) + + def test_close_order_refuse(self): + path = '/intern/status_final/' + self.v.status = Veranstaltung.STATUS_BESTELLUNG_LIEGT_VOR + self.v.save() + + response = self.client.post(path, {'auswahl': 'nein', 'submit': 'Bestätigen'}, **{'REMOTE_USER': 'super'}) + + self.v.refresh_from_db() + self.assertEqual(response.status_code, 302) + self.assertEqual(self.v.status, Veranstaltung.STATUS_BESTELLUNG_LIEGT_VOR) + + +class InternMiscTest(NonSuTestMixin, TestCase): + def test_index(self): + path = tests.INDEX_END + self.do_non_su_test(path) + self.client.login(username='supers', password='pw') + + s = Semester.objects.create(semester=20110, fragebogen='2009', sichtbarkeit='ADM') + + response = self.client.get(path, **{'REMOTE_USER': 'super'}) + self.assertEqual(response.templates[0].name, 'intern/index.html') + self.assertEqual(response.context['cur_semester'], s) + + def test_fragebogensprache(self): + path = '/intern/fragebogensprache/' + self.do_non_su_test(path) + self.client.login(username='supers', password='pw') + + Semester.objects.create(semester=20110, fragebogen='2009', sichtbarkeit='ADM') + + response = self.client.get(path, **{'REMOTE_USER': 'super'}) + self.assertEqual(response.templates[0].name, 'intern/fragebogensprache.html') + + def test_export_veranstaltungen_get(self): + path = '/intern/export_veranstaltungen/' + self.do_non_su_test(path) + self.client.login(username='supers', password='pw') + + response = self.client.get(path, **{'REMOTE_USER': 'super'}) + self.assertEqual(response.templates[0].name, 'intern/export_veranstaltungen.html') + self.assertSequenceEqual(response.context['semester'], list(Semester.objects.all())) + + +class ExportVeranstaltungenTest(NonSuTestMixin, TestCase): + def test_export_veranstaltungen_post(self): + path = '/intern/export_veranstaltungen/' + self.client.login(username='supers', password='pw') + self.client.login(username='supers', password='pw') + + _, v1 = get_veranstaltung('v') + s, v2 = get_veranstaltung('vu') + empty_semester = Semester.objects.create(semester=20120, fragebogen='2009', sichtbarkeit='ADM') + + p = Person.objects.create(vorname='Je', nachname='Mand', email='je@ma.nd', geschlecht='w') + v1.veranstalter.add(p) + v2.veranstalter.add(p) + + v1.grundstudium = True + v1.sprache = 'en' + v1.verantwortlich = p + v1.save() + + # kein Semester angegeben + response = self.client.post(path, **{'REMOTE_USER': 'super'}) + self.assertEqual(response.status_code, 302) + self.assertTrue(response['Location'].endswith('/intern/export_veranstaltungen/')) + + # keine Bestellung vorhanden + response = self.client.post(path, {'semester': s.semester}, **{'REMOTE_USER': 'super'}) + self.assertEqual(response.status_code, 302) + self.assertTrue(response['Location'].endswith('/intern/export_veranstaltungen/')) + + # niemand als Verantwortlicher eingetragen + v1.anzahl = 42 + v1.save() + v2.anzahl = 23 + v2.save() + response = self.client.post(path, {'semester': s.semester}, **{'REMOTE_USER': 'super'}) + self.assertEqual(response.status_code, 302) + self.assertTrue(response['Location'].endswith('/intern/export_veranstaltungen/')) + + response = self.client.post(path, {'semester': empty_semester.semester, 'xml_ubung': True}, **{'REMOTE_USER': 'super'}) + self.assertEqual(response.status_code, 302) + self.assertTrue(response['Location'].endswith('/intern/export_veranstaltungen/')) + + # keine Sprache angegeben + v2.verantwortlich = p + v2.save() + response = self.client.post(path, {'semester': s.semester}, **{'REMOTE_USER': 'super'}) + self.assertEqual(response.status_code, 302) + self.assertTrue(response['Location'].endswith('/intern/export_veranstaltungen/')) + + # alles OK + v2.sprache = 'de' + v2.save() + response = self.client.post(path, {'semester': s.semester}, **{'REMOTE_USER': 'super'}) + self.assertRegexpMatches(response['Content-Disposition'], + r'^attachment; filename="[a-zA-Z0-9_-]+\.xml"$') + + self.assertXMLEqual(response.content, + ''' + + + + + +Stoning I +FB 20 +123v-SS11 +SS11 +Vorlesung +42 +Informatik + + + +lv-1 + + +FB20Vv1e +SS11 +coversheet +0 + + + + + +Stoning I +FB 20 +123vu-SS11 +SS11 +Vorlesung + Übung +23 +Informatik + + + +lv-2 + + +FB20Vv1 +SS11 +coversheet +0 + + +''') + response = self.client.post(path, {'semester': s.semester, 'xml_ubung': True}, **{'REMOTE_USER': 'super'}) + self.assertRegexpMatches(response['Content-Disposition'], + r'^attachment; filename="[a-zA-Z0-9_-]+\.xml"$') + + self.assertXMLEqual(response.content, ''' + + + + + +Stoning I +FB 20 +123vu-SS11 +SS11 +Vorlesung + Übung +23 +Informatik + + + +lv-2 + + +FB20\xc3\x9cv1 +SS11 +coversheet +0 + + +''') + + def test_export_veranstaltungen_post_primaerdozent(self): + path = '/intern/export_veranstaltungen/' + self.client.login(username='supers', password='pw') + + s, v = get_veranstaltung('v') + p1 = Person.objects.create(vorname='Je', nachname='Mand', email='je@ma.nd', geschlecht='w') + p2 = Person.objects.create(vorname='Prim', nachname='Ardozent', email='prim@ardoz.ent', geschlecht='m') + p3 = Person.objects.create(vorname='Je1', nachname='Mand1', email='je1@ma.nd', geschlecht='m') + + v.veranstalter.add(p1) + v.veranstalter.add(p2) + v.veranstalter.add(p3) + v.ergebnis_empfaenger.add(p1) + v.ergebnis_empfaenger.add(p2) + v.ergebnis_empfaenger.add(p3) + + v.grundstudium = True + v.sprache = 'en' + v.verantwortlich = p1 + v.primaerdozent = p2 + v.anzahl = 42 + v.save() + + response = self.client.post(path, {'semester': s.semester}, **{'REMOTE_USER': 'super'}) + self.assertRegexpMatches(response['Content-Disposition'], + r'^attachment; filename="[a-zA-Z0-9_-]+\.xml"$') + + self.assertXMLEqual(response.content, + ''' + + + + + + + + + + + + + +Stoning I +FB 20 +123v-SS11 +SS11 +Vorlesung +42 +Informatik + + + +lv-1 + + +FB20Vv1e +SS11 +coversheet +0 + + +Je +Mand +je@ma.nd +f +pe-1 + +Prim +Ardozent +prim@ardoz.ent +m +pe-2 + +Je1 +Mand1 +je1@ma.nd +m +pe-3 + + +''') + + +# +class ImportErgebnisseTest(NonSuTestMixin, TestCase): + def setUp(self): + super(ImportErgebnisseTest, self).setUp() + self.path = '/intern/import_ergebnisse/' + self.s = Semester.objects.create(semester=20110, fragebogen='2009', sichtbarkeit='ADM') + + def test_get(self): + self.do_non_su_test(self.path) + self.client.login(username='supers', password='pw') + + response = self.client.get(self.path, **{'REMOTE_USER': 'super'}) + self.assertEqual(response.templates[0].name, 'intern/import_ergebnisse.html') + self.assertSequenceEqual(response.context['semester'], [self.s]) + self.assertTrue(isinstance(response.context['form'], UploadFileForm)) + + def test_post(self): + self.client.login(username='supers', password='pw') + default_params = {'semester': self.s, 'grundstudium': False, 'evaluieren': True} + Veranstaltung.objects.create(name='Test I', lv_nr='1', **default_params) + + # kein Semester angegeben + response = self.client.post(self.path, **{'REMOTE_USER': 'super'}) + self.assertEqual(response.status_code, 302) + self.assertTrue(response['Location'].endswith('/intern/import_ergebnisse/')) + + # unvollständiges Formular + response = self.client.post(self.path, {'semester': self.s.semester, 'file': ''}, **{'REMOTE_USER': 'super'}) + self.assertEqual(response.templates[0].name, 'intern/import_ergebnisse.html') + + # fehlerhafte Datei angegeben + f = StringIO('b;l;a;b;l;a;b;l;a') + f.name = 'test.csv' + response = self.client.post(self.path, {'semester': self.s.semester, 'file': f}, **{'REMOTE_USER': 'super'}) + f.close() + self.assertEqual(response.status_code, 302) + self.assertTrue(response['Location'].endswith('/intern/sync_ergebnisse/')) + + # alles OK + with open(settings.TESTDATA_PATH + 'ergebnis_test_20115.csv', 'r') as f: + response = self.client.post(self.path, {'semester': self.s.semester, 'file': f}, **{'REMOTE_USER': 'super'}) + self.assertEqual(response.status_code, 302) + self.assertTrue(response['Location'].endswith('/intern/sync_ergebnisse/')) + + +class SyncErgebnisseTest(NonSuTestMixin, TestCase): + def setUp(self): + super(SyncErgebnisseTest, self).setUp() + self.path = '/intern/sync_ergebnisse/' + self.s, self.v = get_veranstaltung('v') + + def test_get(self): + self.do_non_su_test(self.path) + self.client.login(username='supers', password='pw') + + response = self.client.get(self.path, **{'REMOTE_USER': 'super'}) + self.assertEqual(response.templates[0].name, 'intern/sync_ergebnisse.html') + self.assertSequenceEqual(response.context['semester'], [self.s]) + + def test_post(self): + self.client.login(username='supers', password='pw') + + # kein Semester angegeben + response = self.client.post(self.path, **{'REMOTE_USER': 'super'}) + self.assertEqual(response.status_code, 302) + self.assertTrue(response['Location'].endswith('/intern/sync_ergebnisse/')) + + # keine Ergebnisse gefunden + response = self.client.post(self.path, {'semester': self.s.semester}, **{'REMOTE_USER': 'super'}) + self.assertEqual(response.status_code, 302) + self.assertTrue(response['Location'].endswith('/intern/sync_ergebnisse/')) + + # alles OK + Fragebogen2009.objects.create(veranstaltung=self.v, ue_gesamt=1, + ue_e=2, ue_f=3, + ue_a=4, ue_b=5, ue_c=1, ue_d=2, + ue_g=3, ue_i=4, ue_j=5, ue_k=1) + response = self.client.post(self.path, {'semester': self.s.semester}, **{'REMOTE_USER': 'super'}) + self.assertEqual(response.status_code, 302) + self.assertTrue(response['Location'].endswith('/intern/sync_ergebnisse/')) + + +class SendmailTest(NonSuTestMixin, TestCase): + path = '/intern/sendmail/' + + def test_get(self): + self.do_non_su_test(self.path) + self.client.login(username='supers', password='pw') + + response = self.client.get(self.path, **{'REMOTE_USER': 'super'}) + self.assertEqual(response.templates[0].name, 'intern/sendmail.html') + + def test_post(self): + self.client.login(username='supers', password='pw') + get_veranstaltung('v') + s, v1 = get_veranstaltung('vu') + v1.anzahl = 42 + v1.sprache = 'de' + v1.save() + + fb = Fachgebiet.objects.create(name="Fachgebiet1", kuerzel="FB1") + FachgebietEmail.objects.create(fachgebiet=fb, email_suffix="ul.bla", email_sekretaerin="sek@ul.bla") + p1 = Person.objects.create(vorname='Pe', nachname='Ter', email='pe@ter.bla') + p2 = Person.objects.create(vorname='Pa', nachname='Ul', email='pa@ul.bla', fachgebiet=fb) + + v1.veranstalter.add(p1) + v1.veranstalter.add(p2) + mv = Mailvorlage.objects.create(subject='Testmail', body='Dies ist eine Testmail.') + Einstellung.objects.create(name='bestellung_erlaubt', wert='0') + + params = {'uebernehmen': 'x', 'recipient': 'cur_sem_missing_order', 'subject': 'abc', 'body': 'xyz'} + + # kein Semester angegeben + response = self.client.post(self.path, params, **{'REMOTE_USER': 'super'}) + self.assertEqual(response.status_code, 302) + self.assertTrue(response['Location'].endswith('/intern/sendmail/')) + + # Vorlage übernehmen; Vorlage nicht angegeben + params['semester'] = s.semester + response = self.client.post(self.path, params, **{'REMOTE_USER': 'super'}) + self.assertEqual(response.status_code, 302) + self.assertTrue(response['Location'].endswith('/intern/sendmail/')) + + # Vorlage übernehmen; Vorlage ist angegeben + params['vorlage'] = mv.id + response = self.client.post(self.path, params, **{'REMOTE_USER': 'super'}) + self.assertEqual(response.templates[0].name, 'intern/sendmail.html') + self.assertEqual(response.context['subject'], mv.subject) + self.assertEqual(response.context['body'], mv.body) + + # Vorschau; Empfänger ist auf Veranstalter mit fehlenden Bestellungen eingestellt + del params['uebernehmen'] + params['vorschau'] = 'x' + response = self.client.post(self.path, params, **{'REMOTE_USER': 'super'}) + self.assertIn('intern/sendmail_preview.html', (t.name for t in response.templates)) + self.assertTrue(response.context['vorschau']) + + # Vorschau; Empfänger ist auf Veranstaltungen mit Ergebnissen eingestellt + params['recipient'] = 'cur_sem_results' + response = self.client.post(self.path, params, **{'REMOTE_USER': 'super'}) + self.assertIn('intern/sendmail_preview.html', (t.name for t in response.templates)) + self.assertTrue(response.context['vorschau']) + + # Vorschau: Check if the replacements are highlighted + color_span = '{}' + self.assertEqual(color_span.format('Grundlagen der Agrarphilosophie I') , response.context['veranstaltung']) + link_veranstalter = 'https://www.fachschaft.informatik.tu-darmstadt.de%s' % reverse('veranstalter-login') + link_suffix_format = '?vid=%d&token=%s' + self.assertEqual(color_span.format(link_veranstalter + (link_suffix_format % (1337, '0123456789abcdef'))) , response.context['link_veranstalter']) + + # Senden + del params['vorschau'] + params['senden'] = 'x' + params['recipient'] = 'cur_sem_all' + del params['vorlage'] + response = self.client.post(self.path, params, **{'REMOTE_USER': 'super'}) + self.assertEqual(response.status_code, 302) + self.assertTrue(response['Location'], tests.LOGIN_URL) + # Hier wird in Eclipse ein Fehler angezeigt; mail.outbox gibt es während der Testläufe + # aber wirklich (siehe https://docs.djangoproject.com/en/1.4/topics/testing/#email-services) + self.assertEqual(len(mail.outbox), 2) + self.assertEqual(len(mail.outbox[0].to), 3) # an zwei veranstalter und sekretaerin diff --git a/src/feedback/views/intern/__init__.py b/src/feedback/views/intern/__init__.py index 74d3bc3c..ddb686df 100644 --- a/src/feedback/views/intern/__init__.py +++ b/src/feedback/views/intern/__init__.py @@ -1,6 +1,5 @@ # coding=utf-8 -import csv import os import subprocess @@ -14,21 +13,25 @@ from django.template import RequestContext from django.utils.encoding import smart_str from django.views.decorators.http import require_safe, require_http_methods +from django.contrib.auth.mixins import UserPassesTestMixin +from django.views.generic import FormView from feedback import tools +from feedback.forms import CloseOrderForm from feedback.parser.ergebnisse import parse_ergebnisse from feedback.models import Veranstaltung, Semester, Einstellung, Mailvorlage, get_model, long_not_ordert, FachgebietEmail from feedback.forms import UploadFileForm from feedback.views import public from django.db.models import Q + @user_passes_test(lambda u: u.is_superuser) @require_safe def index(request): cur_semester = Semester.current() all_veranst = Veranstaltung.objects.filter(semester=cur_semester) - #Veranstaltung für die es Rückmeldungen gibt + # Veranstaltung für die es Rückmeldungen gibt ruck_veranst = all_veranst.filter(Q(anzahl__gt=0)|Q(evaluieren=False)) num_all_veranst = all_veranst.count() @@ -36,7 +39,7 @@ def index(request): relativ_result = 0 - if (num_all_veranst >= 1): + if num_all_veranst >= 1: relativ_result = (100/float(num_all_veranst)) * num_ruck_veranst width_progressbar = 500 @@ -49,11 +52,13 @@ def index(request): 'width_progressbar': width_progressbar, 'width_progressbar_success': width_progressbar_success,}) + @user_passes_test(lambda u: u.is_superuser) @require_safe def lange_ohne_evaluation(request): return render(request, 'intern/lange_ohne_evaluation.html', {'veranstaltungen': long_not_ordert()}) + @user_passes_test(lambda u: u.is_superuser) @require_safe def fragebogensprache(request): @@ -64,6 +69,7 @@ def fragebogensprache(request): data = {'veranstaltungen': veranstaltungen} return render(request, 'intern/fragebogensprache.html', data) + @user_passes_test(lambda u: u.is_superuser) @require_http_methods(('HEAD', 'GET', 'POST')) def export_veranstaltungen(request): @@ -111,10 +117,11 @@ def export_veranstaltungen(request): person_set = set() - data = {} + data = { + 'veranst': veranst, + 'ubung_export': ubung_export + } - data['veranst'] = veranst - data['ubung_export'] = ubung_export for ver in veranst: for cur_empf in ver.ergebnis_empfaenger.all(): person_set.add(cur_empf) @@ -135,24 +142,28 @@ def export_veranstaltungen(request): def translate_to_latex(text): - dic = {'&':'\&', - '%':'\%', - '$':'\$', - '#':'\#', - '_':'\_', - '"':'"{}', - '~':'\~{}', - '^':'\\textasciicircum', + dic = { + '&': '\&', + '%': '\%', + '$': '\$', + '#': '\#', + '_': '\_', + '"': '"{}', + '~': '\~{}', + '^': '\\textasciicircum', } + for i, j in dic.iteritems(): text = text.replace(i, j) return text + @user_passes_test(lambda u: u.is_superuser) @require_http_methods(('HEAD', 'GET', 'POST')) def generate_letters(request): - data = {} - data['semester'] = Semester.objects.all() + data = { + 'semester': Semester.objects.all() + } datefilename = settings.LATEX_PATH + 'erhebungswoche.inc' @@ -184,7 +195,7 @@ def generate_letters(request): templatename = 'aufkleber' # aus Sicherheitsgründen TeX-Befehle in Abgabedatum-String deaktivieren - #TODO: Kalender-Widget einführen, nur noch dessen Format akzeptieren + # TODO: Kalender-Widget einführen, nur noch dessen Format akzeptieren try: abgabedatum = request.POST['erhebungswoche'].replace('\\', '') except KeyError: @@ -194,6 +205,7 @@ def generate_letters(request): response = HttpResponse(content_type='application/pdf') response['Content-Disposition'] = 'attachment; filename=%s.pdf' % (templatename) + if vorlage != 'Aufkleber': veranst = Veranstaltung.objects.filter(semester=semester, evaluieren=True, anzahl__gt=0).order_by('sprache','anzahl') elif 'anzahlaufkleber' in request.POST and request.POST['anzahlaufkleber'].isdigit(): @@ -202,19 +214,20 @@ def generate_letters(request): veranst = Veranstaltung.objects.filter(semester=semester, evaluieren=True, anzahl__gt=anzahl).order_by('sprache','anzahl') else: veranst = Veranstaltung.objects.filter(semester=semester, evaluieren=True, anzahl__gt=0).order_by('sprache','anzahl') + if not veranst.count(): messages.error(request, 'Für das ausgewählte Semester (%s) liegen keine Bestellungen vor oder die Mindesteilnehmeranzahl ist zu hoch!' % semester) return HttpResponseRedirect(reverse('generate_letters')) lines = [] for v in veranst: - eva_id=v.get_barcode_number() + eva_id = v.get_barcode_number() empfaenger = unicode(v.verantwortlich.full_name()) line = u'\\adrentry{%s}{%s}{%s}{%s}{%s}{%s}{%s}{%s}{%s}\n' % ( translate_to_latex(v.verantwortlich.full_name()), translate_to_latex(v.verantwortlich.anschrift), translate_to_latex(v.name), v.anzahl, v.sprache, v.get_typ_display(), eva_id, v.freiefrage1.strip(), v.freiefrage2.strip()) lines.append(smart_str(line)) - #TODO: prüfen, ob nötige Dateien schreibbar sind (abgabedatum.inc, anschreiben.{log,aux,pdf}, veranstalter.adr) + # TODO: prüfen, ob nötige Dateien schreibbar sind (abgabedatum.inc, anschreiben.{log,aux,pdf}, veranstalter.adr) with open(latexpath + 'veranstalter.adr', 'w') as f: f.writelines(lines) @@ -234,12 +247,14 @@ def generate_letters(request): response.write(f.read()) return response + @user_passes_test(lambda u: u.is_superuser) @require_http_methods(('HEAD', 'GET', 'POST')) def sendmail(request): - data = {} - data['semester'] = Semester.objects.order_by('-semester') - data['vorlagen'] = Mailvorlage.objects.all() + data = { + 'semester': Semester.objects.order_by('-semester'), + 'vorlagen': Mailvorlage.objects.all() + } if request.method == 'POST': try: @@ -357,9 +372,10 @@ def import_ergebnisse(request): if form.is_valid(): warnings, errors, vcount, fbcount = parse_ergebnisse(semester, request.FILES['file']) if fbcount: - messages.success(request, - u'%u Veranstaltungen mit insgesamt %u Fragebögen wurden erfolgreich importiert.' % - (vcount, fbcount)) + messages.success( + request, + u'%u Veranstaltungen mit insgesamt %u Fragebögen wurden erfolgreich importiert.' % (vcount, fbcount) + ) else: warnings.append(u'Es konnten keine Fragebögen importiert werden.') @@ -376,6 +392,7 @@ def import_ergebnisse(request): return render(request, 'intern/import_ergebnisse.html', data) + @user_passes_test(lambda u: u.is_superuser) @require_http_methods(('HEAD', 'GET', 'POST')) def sync_ergebnisse(request): @@ -388,21 +405,21 @@ def sync_ergebnisse(request): except (Semester.DoesNotExist, KeyError): return HttpResponseRedirect(reverse('sync_ergebnisse')) - Fragebogen = get_model('Fragebogen', semester) - Ergebnis = get_model('Ergebnis', semester) - Ergebnis.objects.filter(veranstaltung__semester=semester).delete() + fragebogen = get_model('Fragebogen', semester) + ergebnis = get_model('Ergebnis', semester) + ergebnis.objects.filter(veranstaltung__semester=semester).delete() found_something = False for v in Veranstaltung.objects.filter(semester=semester): - fbs = Fragebogen.objects.filter(veranstaltung=v) + fbs = fragebogen.objects.filter(veranstaltung=v) if len(fbs): found_something = True data = {'veranstaltung': v, 'anzahl': len(fbs)} - for part in Ergebnis.parts + Ergebnis.hidden_parts: - result, count = tools.get_average(Ergebnis, fbs, part[0]) + for part in ergebnis.parts + ergebnis.hidden_parts: + result, count = tools.get_average(ergebnis, fbs, part[0]) data[part[0]] = result data[part[0]+'_count'] = count - Ergebnis.objects.create(**data) + ergebnis.objects.create(**data) if not found_something: messages.warning(request, u'Für das %s liegen keine Ergebnisse vor.' % semester) @@ -410,6 +427,59 @@ def sync_ergebnisse(request): messages.success(request, u'Das Ranking für das %s wurde erfolgreich berechnet.' % semester) return HttpResponseRedirect(reverse('sync_ergebnisse')) + @user_passes_test(lambda u: u.is_superuser) def ergebnisse(request): return public.index(request) + + +def is_no_evaluation_final(status): + return status == Veranstaltung.STATUS_KEINE_EVALUATION or status == Veranstaltung.STATUS_ANGELEGT or \ + status == Veranstaltung.STATUS_BESTELLUNG_GEOEFFNET + + +def update_veranstaltungen_status(veranstaltungen): + for v in veranstaltungen: + if is_no_evaluation_final(v.status): + v.status = Veranstaltung.STATUS_KEINE_EVALUATION_FINAL + v.save() + elif v.status == Veranstaltung.STATUS_BESTELLUNG_LIEGT_VOR: + v.status = Veranstaltung.STATUS_BESTELLUNG_WIRD_VERARBEITET + v.save() + + +class CloseOrderFormView(UserPassesTestMixin, FormView): + template_name = 'intern/status_final.html' + form_class = CloseOrderForm + + def post(self, request, *args, **kwargs): + form_class = self.get_form_class() + form = self.get_form(form_class) + if form.is_valid: + choice = self.get_form_kwargs().get('data').get('auswahl') + if choice == 'ja': + return self.form_valid(form) + else: + return self.form_invalid(form) + + def form_valid(self, form): + update_veranstaltungen_status(self.get_queryset()) + messages.success(self.request, u'Alle Status wurden erfolgreich aktualisiert.') + return super(CloseOrderFormView, self).form_valid(form) + + def form_invalid(self, form): + return HttpResponseRedirect(reverse('intern-index')) + + def get_queryset(self): + try: + veranstaltungen = Veranstaltung.objects.filter(semester=Semester.current()) + return veranstaltungen + except (Veranstaltung.DoesNotExist, KeyError): + messages.warning(self.request, u'Keine passenden Veranstaltungen für das aktuelle Semester gefunden.') + return HttpResponseRedirect(reverse('intern-index')) + + def get_success_url(self): + return reverse('intern-index') + + def test_func(self): + return self.request.user.is_superuser diff --git a/src/feedback/views/veranstalter.py b/src/feedback/views/veranstalter.py index dc31ba75..a59d10ef 100644 --- a/src/feedback/views/veranstalter.py +++ b/src/feedback/views/veranstalter.py @@ -46,9 +46,8 @@ def veranstalter_dashboard(request): data["logs"] = Log.objects.filter(veranstaltung=veranst).order_by('timestamp') data["allow_order"] = veranst.allow_order() - if veranst.status >= Veranstaltung.STATUS_BESTELLUNG_GEOEFFNET: - bestellung = [] - bestellung.append(("Evaluieren", veranst.get_evaluieren_display)) + if veranst.status >= Veranstaltung.STATUS_BESTELLUNG_LIEGT_VOR: + bestellung = [("Evaluieren", veranst.get_evaluieren_display)] if veranst.evaluieren: bestellung.append(("Typ", veranst.get_typ_display)) bestellung.append(("Anazhl", veranst.anzahl)) diff --git a/src/templates/intern/index.html b/src/templates/intern/index.html index 2dc7d4b3..1757eed2 100644 --- a/src/templates/intern/index.html +++ b/src/templates/intern/index.html @@ -1,35 +1,43 @@ -{% extends "bestellung_base.html" %} {% block title %}Interner Bereich{% endblock %} {% block content %} -

Interner Bereich

- -

Status der Rückmeldungen durch die Veranstalter

-

Aktuell haben wir {{ruck_veranst}} Rückmeldungen von {{all_veranst}} Veranstaltungen.

-
-
-

{{relativ_result|floatformat:-2}}%

+{% extends "bestellung_base.html" %} +{% load static %} +{% block title %} + Interner Bereich +{% endblock %} + +{% block content %} +

Interner Bereich

+ +

Status der Rückmeldungen durch die Veranstalter

+

Aktuell haben wir {{ruck_veranst}} Rückmeldungen von {{all_veranst}} Veranstaltungen.

+
+
+

{{relativ_result|floatformat:-2}}%

+
-
-

Ablauf

-

Dies sind nicht alle nötigen Schritte; siehe Ablauf im Trac.

-
    -
  1. neues Semester anlegen (aktuell: - {% if cur_semester %}{{cur_semester.short}}{% else %}nicht Vorhanden{% endif %})
  2. -
  3. Veranstaltungen aus VV importieren (vor Bestellphase)
  4. -
  5. Fehlende Personendaten nachtragen (vor Bestellphase)
  6. -
  7. Anschreiben für Veranstalter erzeugen (nach Bestellphase)
  8. -
  9. Veranstaltungen für EvaSys exportieren (vor dem Scannen)
  10. -
  11. Ergebnisse aus EvaSys importieren (nach dem Scannen)
  12. -
  13. Rankings berechnen (nach dem Ergebnis-Import)
  14. - {% if cur_semester %} -
  15. Ergebnisse veröffentlichen (aktuell: sichtbar für {{cur_semester.get_sichtbarkeit_display}})
  16. - {% endif %} -
+

Ablauf

+

Dies sind nicht alle nötigen Schritte; siehe Ablauf im Trac.

+ +
    +
  1. neues Semester anlegen (aktuell: + {% if cur_semester %}{{cur_semester.short}}{% else %}nicht Vorhanden{% endif %})
  2. +
  3. Veranstaltungen aus VV importieren (vor Bestellphase)
  4. +
  5. Fehlende Personendaten nachtragen (vor Bestellphase)
  6. +
  7. Bestellphase abschließen (nach Bestellphase)
  8. +
  9. Anschreiben für Veranstalter erzeugen (nach Bestellphase)
  10. +
  11. Veranstaltungen für EvaSys exportieren (vor dem Scannen)
  12. +
  13. Ergebnisse aus EvaSys importieren (nach dem Scannen)
  14. +
  15. Rankings berechnen (nach dem Ergebnis-Import)
  16. + {% if cur_semester %} +
  17. Ergebnisse veröffentlichen (aktuell: sichtbar für {{cur_semester.get_sichtbarkeit_display}})
  18. + {% endif %} +
{% endblock %} {% block backlink %}{% endblock %} diff --git a/src/templates/intern/status_final.html b/src/templates/intern/status_final.html new file mode 100644 index 00000000..026d7390 --- /dev/null +++ b/src/templates/intern/status_final.html @@ -0,0 +1,15 @@ +{% extends "bestellung_base.html" %} +{% load static %} +{% block title %} + Interner Bereich +{% endblock %} + +{% block content %} +

Bestellphase abschließen?

+

Sie sind dabei die Bestellphase zu beenden. Möchten Sie das wirklich tun?

+
+ {% csrf_token %} + {{ form.as_p }} +   +
+{% endblock %} \ No newline at end of file diff --git a/src/urls.py b/src/urls.py index 966a4b02..2d3f4b96 100644 --- a/src/urls.py +++ b/src/urls.py @@ -63,6 +63,7 @@ url(r'^intern/export_veranstaltungen/$', feedback.views.intern.export_veranstaltungen, name='export_veranstaltungen'), url(r'^intern/generate_letters/$', feedback.views.intern.generate_letters, name='generate_letters'), url(r'^intern/import_ergebnisse/$', feedback.views.intern.import_ergebnisse, name='import_ergebnisse'), + url(r'^intern/status_final/$', feedback.views.intern.CloseOrderFormView.as_view(), name='status_final'), url(r'^intern/sync_ergebnisse/$', feedback.views.intern.sync_ergebnisse, name='sync_ergebnisse'), url(r'^intern/fragebogensprache/$', feedback.views.intern.fragebogensprache, name='fragebogensprache'), url(r'^intern/lange_ohne_evaluation/$', feedback.views.intern.lange_ohne_evaluation, name='lange_ohne_evaluation'),