From 04192bc21af6ebcb0bbe1001d8b4ad4dfa00b2f6 Mon Sep 17 00:00:00 2001
From: "robinwilliam.hundt" <robinwilliam.hundt@stud.uni-goettingen.de>
Date: Tue, 14 Jan 2020 16:41:51 +0100
Subject: [PATCH] Added util command to postprocess hektor export for exercises

An example:

./manage.py process_ilias_exercise ~/grady-data/info-1-uebung8.json /home/robin/Downloads/1578407820__9310__tst__results_129758.csv  ~/grady-data/grady-uebungen-teilnehmer.csv test.json --previous-hektor-files ~/grady-data/info-1-uebung5.json ~/grady-data/info-1-uebung6.json

when passing --sent-mail, an email is automatically sent to every new user
---
 .../commands/process_ilias_exercise.py        | 149 ++++++++++++++++++
 1 file changed, 149 insertions(+)
 create mode 100644 core/management/commands/process_ilias_exercise.py

diff --git a/core/management/commands/process_ilias_exercise.py b/core/management/commands/process_ilias_exercise.py
new file mode 100644
index 00000000..b2ec3470
--- /dev/null
+++ b/core/management/commands/process_ilias_exercise.py
@@ -0,0 +1,149 @@
+"""
+This is a small utility script intended for the processing of an ilias export of an
+exercise. At the moment it is intended for the ongoing CS 1 exercises.
+
+"""
+
+import csv
+import json
+import smtplib
+import ssl
+from getpass import getpass
+
+from django.core.management.base import BaseCommand
+from util.factories import get_random_password
+
+
+class Command(BaseCommand):
+    help = 'Process an ILIAS export already converted by Hektor to set groups, etc. . ' \
+           'Note that every student in the hektor data needs to have an email that is consistent ' \
+           'with the other files!'
+
+    def add_arguments(self, ap):
+        ap.add_argument(
+            'hektor-output',
+            help='Path to current Hektor export that should be processed'
+        )
+
+        ap.add_argument(
+            'ilias-results-csv',
+            help='Csv file generated by Ilias when selecting "Erstelle Exportdatei"'
+        )
+
+        ap.add_argument(
+            'group-data',
+            help='Group data csv file sent by Lecturer'
+        )
+
+        ap.add_argument(
+            '--previous-hektor-files',
+            nargs='*',
+            help='Provide previous processed export files in order to only '
+                 'set passwords for students who have not been in export before'
+        )
+
+        ap.add_argument(
+            'out-path',
+            help='Where to write the processed file'
+        )
+
+        ap.add_argument(
+            '--sent-mail',
+            action='store_true',
+            help='Sends mails to student with passwords after processing. Note that you should '
+                 'import the generated file shortly after this, because only then are the '
+                 'accounts actually created'
+        )
+
+    def handle(self, *args, **options):
+        with open(options['hektor-output']) as f:
+            hektor_data = json.load(f)
+
+        previous_data = []
+        if options['previous_hektor_files'] is not None:
+            for path in options['previous_hektor_files']:
+                with open(path) as f:
+                    previous_data.append(json.load(f))
+
+        with open(options['ilias-results-csv']) as f:
+            reader = csv.DictReader(f, delimiter=';')
+            ilias_data = {row['Name']: row for row in reader}
+
+        with open(options['group-data']) as f:
+            reader = csv.DictReader(f, delimiter=';')
+            group_data = {row['Email']: row for row in reader}
+
+        for stud in hektor_data['students']:
+            stud_in_group_data = group_data.get(stud['email'], None)
+            stud_in_ilias_data = ilias_data[stud['fullname']]
+            stud['username'] = stud_in_ilias_data['Benutzername']
+            if stud_in_group_data is not None:
+                stud['exercise_groups'] = [stud_in_group_data['Uebung']]
+            else:
+                stud['exercise_groups'] = ["Ohne Ãœbung"]
+
+            student_in_previous_data = [find_student(stud, old_data) for old_data in previous_data]
+
+            if all(stud is None for stud in student_in_previous_data):
+                stud['password'] = get_random_password()
+
+        with open(options['out-path'], 'w') as f:
+            json.dump(hektor_data, f, indent=True, ensure_ascii=False)
+
+        if options['sent_mail']:
+            send_mail(hektor_data)
+
+
+def find_student(student, export):
+    return next((stud for stud in export['students'] if stud['email'] == student['email']), None)
+
+
+def send_mail(data):
+    smtp_server = "email.gwdg.de"
+    port = 587  # For starttls
+    sender_email = "umin.grady@informatik.uni-goettingen.de"
+    password = getpass("Enter Password for Grady-Email")
+
+    # Create a secure SSL context
+    context = ssl.create_default_context()
+
+    # Try to log in to server and send email
+    try:
+        server = smtplib.SMTP(smtp_server, port)
+        server.ehlo()  # Can be omitted
+        server.starttls(context=context)  # Secure the connection
+        server.ehlo()  # Can be omitted
+        server.login(sender_email, password)
+
+        for student in data['students']:
+            if student.get('password', None) is None:
+                continue
+            print('Mailing:', student['email'])
+            print('---------------------')
+
+            message = f"""\
+Subject: Informatik I - Einsicht der Markdown Aufgabe [Uebung 5]
+
+
+Hallo,
+deine Abgabe zur Markdown Aufgabe der Uebung 8 wird momentan
+ueber Grady ( https://gitlab.gwdg.de/j.michal/grady ) korrigiert.
+Du kannst deine korrigierte Abgabe einsehen wenn du dich mit den folgenden Zugangsdaten anmeldest.
+
+URL: https://grady.informatik.uni-goettingen.de/cs1-ue/wise1920
+User: {student['username']}
+Passwort: {student['password']}
+
+Sollte deine Abgabe noch nicht korrigiert sein, schau in ein paar Tagen nochmal rein,
+dein Tutor oder deine Tutorin braucht vermutlich einfach noch ein bisschen Zeit.
+
+Liebe Gruesse
+Dominik, Jakob und Robin
+- Grady Entwicklungsteam -
+    """
+            server.sendmail(sender_email, student['email'], message)
+    except Exception as e:
+        # Print any error messages to stdout
+        print(e)
+    finally:
+        server.quit()
-- 
GitLab