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