import os import csv os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'grady.settings') import django import xkcdpass.xkcd_password as xp import getpass import json import argparse from collections import namedtuple django.setup() INFO = 0 HTML_DIR = 'html' SOLUTION_DIR = 'code/code-lsg' wordfile = xp.locate_wordfile() wordlist = xp.generate_wordlist(wordfile=wordfile, min_length=5, max_length=8) from django.contrib.auth.models import Group, User from core.models import Student, Submission, SubmissionType, Feedback if INFO: info = print else: info = lambda _: 0 def parseme(): parser = argparse.ArgumentParser() parser.add_argument( '--superuser', help='Superuser will be created users be created', action='store_true') parser.add_argument( 'DATADIR', help='a folder containing a predefined set of files with information', default='data') parser.add_argument( '-s', '--submissions', help='A file with submission code and student user names', default='submissions.json', metavar='FILE') parser.add_argument( '-t', '--tutors', help='A list of tutor names', default='tutors', metavar="FILE") parser.add_argument( '-r', '--reviewers', help='A list of reviewer names', default='reviewers', metavar="FILE") parser.add_argument( '-st', '--submission_types', help='some kind of descriptions for all the submission types', default='submission_types.csv', metavar="FILE") args = parser.parse_args() args.tutors = os.path.join(args.DATADIR, args.tutors) args.reviewers = os.path.join(args.DATADIR, args.reviewers) args.submissions = os.path.join(args.DATADIR, args.submissions) args.submission_types = os.path.join(args.DATADIR, args.submission_types) return args def add_submission_type(name, score, task_description="__task_description: what the student saw", possible_solution="__possible_solution: a sample solution", correction_guideline="__possible_solution: a way to correct the task",): task, created = SubmissionType.objects.get_or_create(name=name) task.full_score = int(score) task.task_description = task_description task.possible_solution = possible_solution task.correction_guideline = correction_guideline task.save() if created: info(f"- Created Task {task.name}") else: info(f"- Got Task {task.name}") return task def student_has_all_submissions(student): return Submission.objects.filter(student=student).count() \ == SubmissionType.objects.all().count() def add_submission(type, text, student, compiler_output): if student_has_all_submissions(student): return None sub = Submission() sub.type = type sub.text = text sub.student = student sub.pre_corrections = compiler_output sub.save() add_auto_feedback(sub, compiler_output) info(f"- Created Submission of Type {sub.type}") return sub def add_auto_feedback(submission, compiler_output): if submission.text and not compiler_output: return # let the tutor do his job def deduct_feedback_type() -> (str, str): if not submission.text: return Feedback.WAS_EMPTY, Feedback.ACCEPTED elif compiler_output.endswith('DID NOT COMPILE'): return Feedback.DID_NOT_COMPILE, Feedback.NEEDS_REVIEW elif compiler_output.endswith('COULD NOT LINK'): return Feedback.COULD_NOT_LINK, Feedback.NEEDS_REVIEW else: return None, None auto_correct, _ = User.objects.get_or_create(username='auto_correct') feedback = Feedback() feedback.text = "--- Was generated automatically ---" feedback.origin, feedback.status = deduct_feedback_type() if feedback.origin is None and feedback.status is None: return feedback.of_submission = submission feedback.of_tutor = auto_correct feedback.save() if feedback.origin == Feedback.WAS_EMPTY: submission.final_feedback = feedback submission.save() info(f"- Created {feedback.origin} Feedback for Submission {submission}") return feedback def add_student(username, name, matrikel_no): student_group, _ = Group.objects.get_or_create(name='Students') student, created = Student.objects.get_or_create( matrikel_no=matrikel_no, user=add_user(username, student_group) ) if created: student.name = name student.matrikel_no = matrikel_no student.save() return student def add_user(username, group): user, created = User.objects.get_or_create(username=username) if created: password = xp.generate_xkcdpassword(wordlist, numwords=2) login_writer.writerow([username, password]) user.set_password(password) group.user_set.add(user) info(f"- Created user {user} and added him to group {group}") user.save() else: info(f"- User {user} of group {group} was already created.") return user def add_group(group_name): group, _ = Group.objects.get_or_create(name=group_name) info(f"- Created group {group}") return group def create_superuser(): try: User.objects.create_superuser( username='doncamillo', password=getpass.getpass(), email='a@b.com') except Exception as e: info("- Superuser was already created.") return class PopulateDatabase: """docstring for PopulateDatabase""" __slots__ = ( 'args', 'type_dict', 'student_group', 'tutor_group', 'reviewer_group', ) def __init__(self, args): self.args = args self.create_groups() self.create_user_accounts() self.create_submission_types() self.populate_submissions() def create_groups(self): self.student_group = add_group('Students') self.tutor_group = add_group('Tutors') self.reviewer_group = add_group('Reviewers') def create_user_accounts(self): with open(self.args.tutors) as tutors: for tutor in tutors: add_user(tutor.strip(), self.tutor_group) with open(self.args.reviewers) as reviewers: for reviewer in reviewers: add_user(reviewer.strip(), self.reviewer_group) def create_submission_types(self): submission_type = namedtuple('submission_type', 'id name score') with open(args.submission_types) as data: types = list(submission_type(*line.strip().split(', ')) for line in data if line) self.type_dict = {} for t in types: with \ open(os.path.join(self.args.DATADIR, SOLUTION_DIR, t.id + '-lsg.c' )) as lsg, \ open(os.path.join(self.args.DATADIR, HTML_DIR, t.id + '.html' )) as desc: self.type_dict[t.id] = add_submission_type( f"[{t.id}] {t.name}", t.score, desc.read(), lsg.read(), ) def populate_submissions(self): with open(self.args.submissions) as data: stud_data = json.JSONDecoder().decode(data.read()) for user, userdata in stud_data.items(): student = add_student( user, userdata['name'], userdata['matrikel_no']) for s, code in userdata['submissions'].items(): add_submission( self.type_dict[s], code, student, userdata['compiler_output'][s] ) # Start execution here! if __name__ == '__main__': args = parseme() print("Starting population script...") try: login_data_f = open('login_data.csv', 'w') login_writer = csv.writer(login_data_f) login_writer.writerow(['username', 'password']) PopulateDatabase(args) finally: login_data_f.close() create_superuser()