diff --git a/aleksis/apps/untis/util/mysql/api.py b/aleksis/apps/untis/util/mysql/api.py
deleted file mode 100644
index bd067ae0de1a9d5da1dd446c9d0ef95a48ce9bd9..0000000000000000000000000000000000000000
--- a/aleksis/apps/untis/util/mysql/api.py
+++ /dev/null
@@ -1,219 +0,0 @@
-from django.conf import settings
-
-from untisconnect.api_helper import get_term_by_ids, run_using, untis_date_to_date, date_to_untis_date, \
-    untis_split_first
-from aleksis.apps.untis import models
-from timetable.settings import untis_settings
-
-TYPE_TEACHER = 0
-TYPE_ROOM = 1
-TYPE_CLASS = 2
-
-
-def run_all(obj, filter_term=True):
-    return run_default_filter(run_using(obj).all(), filter_term=filter_term)
-
-
-def run_one(obj, filter_term=True):
-    return run_default_filter(run_using(obj), filter_term=filter_term)
-
-
-def run_default_filter(obj, filter_term=True):
-    # Get term by settings in db
-    TERM_ID = untis_settings.term
-    SCHOOLYEAR_ID = untis_settings.school_year  # 20172018
-    TERM = get_term_by_ids(TERM_ID, SCHOOLYEAR_ID)
-    SCHOOL_ID = TERM.school_id  # 705103
-    VERSION_ID = TERM.version_id  # 1
-
-    if filter_term:
-        return obj.filter(school_id=SCHOOL_ID, schoolyear_id=SCHOOLYEAR_ID, version_id=VERSION_ID, term_id=TERM_ID)
-    else:
-        return obj.filter(school_id=SCHOOL_ID, schoolyear_id=SCHOOLYEAR_ID, version_id=VERSION_ID)
-
-
-def row_by_row_helper(db_rows, obj):
-    out_rows = []
-    for db_row in db_rows:
-        o = obj()
-        o.create(db_row)
-        out_rows.append(o)
-    return out_rows
-
-
-def row_by_row(db_ref, obj, filter_term=True):
-    db_rows = run_all(db_ref.objects, filter_term=filter_term)
-    return row_by_row_helper(db_rows, obj)
-
-
-def one_by_id(db_ref, obj):
-    # print(db_ref)
-    if db_ref is not None:
-        o = obj()
-        o.create(db_ref)
-        return o
-    else:
-        return None
-
-
-def format_classes(classes):
-    """
-    Formats a list of Class objects to a combined string
-
-    example return: "9abcd" for classes 9a, 9b, 9c and 9d
-
-    :param classes: Class list
-    :return: combined string
-    """
-    classes_as_dict = {}
-
-    classes = sorted(classes, key=lambda class_: class_.name)
-
-    for _class in classes:
-        step = _class.name[:-1]
-        part = _class.name[-1:]
-        if step not in classes_as_dict.keys():
-            classes_as_dict[step] = [part]
-        else:
-            classes_as_dict[step].append(part)
-
-    out = []
-    for key, value in classes_as_dict.items():
-        out.append(key + "".join(value))
-    return ", ".join(out)
-
-
-class Absence(object):
-    def __init__(self):
-        self.filled = None
-        self.teacher = None
-        self.room = None
-        self.type = TYPE_TEACHER
-        self.from_date = None
-        self.to_date = None
-        self.from_lesson = None
-        self.to_lesson = None
-        self.is_whole_day = None
-
-    def create(self, db_obj):
-        self.filled = True
-        # print(db_obj.ida)
-        # print(db_obj.typea)
-        if db_obj.typea == 101:
-            self.type = TYPE_TEACHER
-        elif db_obj.typea == 100:
-            self.type = TYPE_CLASS
-        elif db_obj.typea == 102:
-            self.type = TYPE_ROOM
-
-        if self.type == TYPE_TEACHER:
-            # print("IDA", db_obj.ida)
-            self.teacher = get_teacher_by_id(db_obj.ida)
-        else:
-            self.room = get_room_by_id(db_obj.ida)
-        self.from_date = untis_date_to_date(db_obj.datefrom)
-        self.to_date = untis_date_to_date(db_obj.dateto)
-        self.from_lesson = db_obj.lessonfrom
-        self.to_lesson = db_obj.lessonto
-        self.is_whole_day = self.from_lesson == 1 and self.to_lesson >= settings.TIMETABLE_HEIGHT
-
-
-def get_all_absences_by_date(date):
-    d_i = int(date_to_untis_date(date))
-    db_rows = run_all(models.Absence.objects.filter(dateto__gte=d_i, datefrom__lte=d_i, deleted=0), filter_term=False)
-    return row_by_row_helper(db_rows, Absence)
-
-
-def get_absence_by_id(id):
-    absence = run_one(models.Absence.objects, filter_term=False).get(absence_id=id)
-    return one_by_id(absence, Absence)
-
-
-#########
-# EVENT #
-#########
-
-class Event(object):
-    def __init__(self):
-        self.filled = None
-        self.text = None
-        self.teachers = []
-        self.classes = []
-        self.rooms = []
-        self.absences = []
-        self.from_date = None
-        self.to_date = None
-        self.from_lesson = None
-        self.to_lesson = None
-        self.is_whole_day = None
-
-    def create(self, db_obj):
-        """0~0~19~0~1859~0,0~0~65~0~1860~0,0~0~21~0~1861~0,0~0~3~0~1862~0"""
-        self.filled = True
-        event_parsed = db_obj.eventelement1.split(",")
-        elements = []
-        for element in event_parsed:
-            elements.append(element.split("~"))
-
-        for element in elements:
-            if element[0] != "0" and element[0] != "":
-                self.classes.append(element[0])
-
-            if element[2] != "0" and element[2] != "":
-                self.teachers.append(element[2])
-
-            if element[3] != "0" and element[3] != "":
-                self.rooms.append(element[3])
-
-            if element[4] != "0" and element[4] != "":
-                self.absences.append(element[4])
-
-        self.text = db_obj.text
-        self.from_date = untis_date_to_date(db_obj.datefrom)
-        self.to_date = untis_date_to_date(db_obj.dateto)
-        self.from_lesson = db_obj.lessonfrom
-        self.to_lesson = db_obj.lessonto
-        self.is_whole_day = self.from_lesson == 1 and self.to_lesson >= settings.TIMETABLE_HEIGHT
-
-
-def get_all_events_by_date(date):
-    d_i = int(date_to_untis_date(date))
-    db_rows = run_all(models.Event.objects.filter(dateto__gte=d_i, datefrom__lte=d_i, deleted=0), filter_term=False)
-    return row_by_row_helper(db_rows, Event)
-
-
-##########
-# LESSON #
-##########
-def get_raw_lessons():
-    return run_all(models.Lesson.objects.filter(deleted=0))
-
-
-###########
-# HOLIDAY #
-###########
-class Holiday(object):
-    def __init__(self):
-        self.filled = False
-        self.name = None
-        self.datefrom = None
-        self.dateto = None
-
-    def __str__(self):
-        if self.filled:
-            return self.name or "Unbekannt"
-        else:
-            return "Unbekannt"
-
-    def create(self, db_obj):
-        self.filled = True
-        self.name = db_obj.name
-        self.datefrom = db_obj.datefrom
-        self.dateto = db_obj.dateto
-
-
-def get_today_holidays(date):
-    # db_holidays = row_by_row(models.Holiday, Holiday)
-    d_i = int(date_to_untis_date(date))
-    db_rows = run_all(models.Holiday.objects.filter(dateto__gte=d_i, datefrom__lte=d_i), filter_term=False)
-    return row_by_row_helper(db_rows, Holiday)
diff --git a/aleksis/apps/untis/util/mysql/events.py b/aleksis/apps/untis/util/mysql/events.py
deleted file mode 100644
index aac03768d4e7f9809a189e7e5f08aa24c3f2f7a8..0000000000000000000000000000000000000000
--- a/aleksis/apps/untis/util/mysql/events.py
+++ /dev/null
@@ -1,87 +0,0 @@
-from django.conf import settings
-
-from schoolapps.settings import TIMETABLE_HEIGHT
-from .drive import drive
-from .util import untis_date_to_date, date_to_untis_date
-from .api import row_by_row_helper, run_all, get_absence_by_id
-from aleksis.apps.untis import models
-
-
-#########
-# EVENT #
-#########
-
-class Event(object):
-    def __init__(self):
-        self.filled = None
-        self.id = None
-        self.text = None
-        self.teachers = []
-        self.classes = []
-        self.rooms = []
-        self.absences = []
-        self.from_date = None
-        self.to_date = None
-        self.from_lesson = None
-        self.to_lesson = None
-        self.is_whole_day = None
-
-    def create(self, db_obj):
-        """0~0~19~0~1859~0,0~0~65~0~1860~0,0~0~21~0~1861~0,0~0~3~0~1862~0"""
-        self.filled = True
-        self.id = db_obj.event_id
-
-        event_parsed = db_obj.eventelement1.split(",")
-        elements = []
-        for element in event_parsed:
-            elements.append(element.split("~"))
-
-        for element in elements:
-            if element[0] != "0" and element[0] != "":
-                class_id = int(element[0])
-                obj = drive["classes"][class_id]
-                self.classes.append(obj)
-
-            if element[2] != "0" and element[2] != "":
-                teacher_id = int(element[2])
-                obj = drive["teachers"][teacher_id]
-                self.teachers.append(obj)
-
-            if element[3] != "0" and element[3] != "":
-                room_id = int(element[3])
-                obj = drive["rooms"][room_id]
-                self.rooms.append(obj)
-
-            if element[4] != "0" and element[4] != "":
-                # print(element[4])
-                try:
-                    absence_id = int(element[4])
-                    absence = get_absence_by_id(absence_id)
-                    self.absences.append(absence)
-                except models.Absence.DoesNotExist:
-                    pass
-        self.text = db_obj.text
-        self.from_date = untis_date_to_date(db_obj.datefrom)
-        self.to_date = untis_date_to_date(db_obj.dateto)
-        self.from_lesson = db_obj.lessonfrom
-        self.to_lesson = db_obj.lessonto
-        self.is_whole_day = self.from_lesson == 1 and self.to_lesson >= settings.TIMETABLE_HEIGHT
-
-
-def get_all_events_by_date(date):
-    d_i = int(date_to_untis_date(date))
-    db_rows = run_all(models.Event.objects.filter(dateto__gte=d_i, datefrom__lte=d_i, deleted=0), filter_term=False)
-    rows = row_by_row_helper(db_rows, Event)
-
-    # Remap the lesson numbers matching for the given date
-    for i, event in enumerate(rows):
-        if event.from_date != event.to_date:
-            if event.from_date == date:
-                event.to_lesson = TIMETABLE_HEIGHT
-            elif event.to_date == date:
-                event.from_lesson = 1
-            else:
-                event.from_lesson = 1
-                event.to_lesson = TIMETABLE_HEIGHT
-
-    return rows
diff --git a/aleksis/apps/untis/util/mysql/sub.py b/aleksis/apps/untis/util/mysql/sub.py
deleted file mode 100644
index 7b9236df619ead2b012683c41c6bb96be969d5f4..0000000000000000000000000000000000000000
--- a/aleksis/apps/untis/util/mysql/sub.py
+++ /dev/null
@@ -1,341 +0,0 @@
-from django.utils import timezone
-from django.db.models import Q
-
-from untisconnect import models
-from untisconnect.api import run_default_filter, row_by_row_helper, format_classes, get_all_absences_by_date, \
-    TYPE_TEACHER
-from untisconnect.api_helper import run_using, untis_split_first, untis_date_to_date, date_to_untis_date
-from untisconnect.parse import get_lesson_element_by_id_and_teacher
-from untisconnect.drive import drive
-
-TYPE_SUBSTITUTION = 0
-TYPE_CANCELLATION = 1
-TYPE_TEACHER_CANCELLATION = 2
-TYPE_CORRIDOR = 3
-
-
-def parse_type_of_untis_flags(flags):
-    """
-    Get type of substitution by parsing UNTIS flags
-    :param flags: UNTIS flags (string)
-    :return: type (int, constants are provided)
-    """
-
-    type_ = TYPE_SUBSTITUTION
-    if "E" in flags:
-        type_ = TYPE_CANCELLATION
-    elif "F" in flags:
-        type_ = TYPE_TEACHER_CANCELLATION
-    return type_
-
-
-class Substitution(object):
-    def __init__(self):
-        self.filled = False
-        self.id = None
-        self.lesson_id = None
-        self.date = None
-        self.lesson = None
-        self.type = None
-        self.text = None
-        self.teacher_old = None
-        self.teacher_new = None
-        self.subject_old = None
-        self.subject_new = None
-        self.room_old = None
-        self.room_new = None
-        self.corridor = None
-        self.classes = None
-        self.lesson_element = None
-        self.lesson_time = None
-
-    def __str__(self):
-        if self.filled:
-            return self.id
-        else:
-            return "Unbekannt"
-
-    def create(self, db_obj):
-        self.filled = True
-
-        # Metadata
-        self.id = db_obj.substitution_id
-        self.lesson_id = db_obj.lesson_idsubst
-        self.date = untis_date_to_date(db_obj.date)
-        self.lesson = db_obj.lesson
-        self.type = parse_type_of_untis_flags(db_obj.flags)
-        self.text = db_obj.text
-
-        # Teacher
-        if db_obj.teacher_idlessn != 0:
-            self.teacher_old = drive["teachers"][db_obj.teacher_idlessn]
-
-        # print(self.teacher_new, self.teacher_old, self.lesson_id, self.id)
-        if db_obj.teacher_idsubst != 0:
-            self.teacher_new = drive["teachers"][db_obj.teacher_idsubst]
-
-            if self.teacher_old is not None and self.teacher_new.id == self.teacher_old.id:
-                self.teacher_new = None
-
-            if self.teacher_old is None and self.teacher_new is not None:
-                self.teacher_old = self.teacher_new
-                self.teacher_new = None
-
-        # print(self.teacher_old, self.teacher_new)
-
-        self.lesson_element, self.room_old = get_lesson_element_by_id_and_teacher(self.lesson_id, self.teacher_old,
-                                                                                  self.lesson, self.date.weekday() + 1)
-
-        # Subject
-        self.subject_old = self.lesson_element.subject if self.lesson_element is not None else None
-        if db_obj.subject_idsubst != 0:
-            self.subject_new = drive["subjects"][db_obj.subject_idsubst]
-
-            if self.subject_old is not None and self.subject_old.id == self.subject_new.id:
-                self.subject_new = None
-
-        # Room
-        if db_obj.room_idsubst != 0:
-            self.room_new = drive["rooms"][db_obj.room_idsubst]
-
-            if self.room_old is not None and self.room_old.id == self.room_new.id:
-                self.room_new = None
-
-        # Supervisement
-        if db_obj.corridor_id != 0:
-            self.corridor = drive["corridors"][db_obj.corridor_id]
-            self.type = TYPE_CORRIDOR
-
-        # Classes
-        self.classes = []
-        class_ids = untis_split_first(db_obj.classids, conv=int)
-
-        for id in class_ids:
-            self.classes.append(drive["classes"][id])
-
-
-def substitutions_sorter(sub):
-    """
-    Sorting helper (sort function) for substitutions
-    :param sub: Substitution to sort
-    :return: A string for sorting by
-    """
-
-    # First, sort by class
-    sort_by = sub.classes
-
-    # If the sub hasn't got a class, then put it to the bottom
-    if sort_by == "":
-        sort_by = "Z"
-
-    # Second, sort by lesson number
-    sort_by += str(sub.lesson)
-
-    return sort_by
-
-
-class SubRow(object):
-    def __init__(self):
-        self.sub = None
-        self.color = "black"
-        self.css_class = "black-text"
-        self.lesson = ""
-        self.classes = ""
-        self.teacher = ""
-        self.teacher_full = ""
-        self.teachers = []  # Only for events
-        self.rooms = []  # Only for events
-        self.absences = []  # Only for events
-        self.subject = ""
-        self.subject_full = ""
-        self.room = ""
-        self.room_full = ""
-        self.text = ""
-        self.extra = ""
-        self.is_event = False
-        self.event = None
-
-
-def generate_event_table(events):
-    sub_rows = []
-    for event in events:
-        sub_row = SubRow()
-        sub_row.is_event = True
-        sub_row.event = event
-
-        if event.from_lesson != event.to_lesson:
-            sub_row.lesson = "{}.-{}.".format(event.from_lesson, event.to_lesson)
-        else:
-            sub_row.lesson = "{}.".format(event.from_lesson)
-
-        sub_row.classes = format_classes(event.classes)
-        sub_row.teachers = event.teachers
-        sub_row.rooms = event.rooms
-        sub_row.absences = event.absences
-
-        sub_row.color = "purple"
-        sub_row.text = event.text
-
-        sub_rows.append(sub_row)
-
-    return sub_rows
-
-
-def generate_sub_table(subs, events=[]):
-    """
-    Parse substitutions and prepare than for displaying in plan
-    :param subs: Substitutions to parse
-    :return: A list of SubRow objects
-    """
-
-    sub_rows = []
-    for sub in subs:
-        sub_row = SubRow()
-        sub_row.sub = sub
-
-        # Color
-        sub_row.color = "black"
-        if sub.type == 1 or sub.type == 2:
-            sub_row.css_class = "green-text"
-            sub_row.color = "green"
-        elif sub.type == 3:
-            sub_row.css_class = "blue-text"
-            sub_row.color = "blue"
-
-        #  Format lesson
-        if sub.type == 3:
-            sub_row.lesson = "{}./{}.".format(sub.lesson - 1, sub.lesson)
-        else:
-            sub_row.lesson = "{}.".format(sub.lesson)
-
-        # Classes
-        sub_row.classes = format_classes(sub.classes)
-
-        # Hint text
-        sub_row.text = sub.text
-
-        # Badge
-        sub_row.badge = None
-        if sub.type == 1:
-            sub_row.badge = "Schüler frei"
-        elif sub.type == 2:
-            sub_row.badge = "Lehrer frei"
-
-        # Debugging information
-        sub_row.extra = "{} {}".format(sub.id, sub.lesson_id)
-
-        sub_rows.append(sub_row)
-
-    sub_rows += generate_event_table(events)
-    sub_rows.sort(key=substitutions_sorter)
-
-    return sub_rows
-
-
-class HeaderInformation:
-    def __init__(self):
-        self.absences = []
-        self.missing_classes = []
-        self.affected_teachers = []
-        self.affected_classes = []
-        self.rows = []
-
-    def is_box_needed(self):
-        return len(self.absences) > 0 or len(self.missing_classes) > 0 or len(
-            self.affected_teachers) > 0 or len(self.affected_classes) > 0
-
-
-def get_header_information(subs, date, events=[]):
-    """
-    Get header information like affected teachers/classes and missing teachers/classes for a given date
-    :param date: The date as datetime object
-    :param subs: All subs for the given date
-    :return: HeaderInformation object with all kind of information
-    """
-
-    info = HeaderInformation()
-
-    # Get all affected teachers and classes
-    for sub in subs:
-        if sub.teacher_old and sub.teacher_old not in info.affected_teachers:
-            info.affected_teachers.append(sub.teacher_old)
-        if sub.teacher_new and sub.teacher_new not in info.affected_teachers:
-            info.affected_teachers.append(sub.teacher_new)
-
-        for _class in sub.classes:
-            if _class not in info.affected_classes:
-                info.affected_classes.append(_class)
-
-    for event in events:
-        for teacher in event.teachers:
-            if teacher.id not in [x.id for x in info.affected_teachers]:
-                info.affected_teachers.append(teacher)
-
-        for _class in event.classes:
-            if _class.id not in [x.id for x in info.affected_classes]:
-                info.affected_classes.append(_class)
-
-    # Get all absences that are relevant for this day
-    info.absences = get_all_absences_by_date(date)
-
-    # Format list of affected teachers
-    if info.affected_teachers:
-        joined = ", ".join(sorted([x.shortcode for x in info.affected_teachers]))
-        info.rows.append(("Betroffene Lehrkräfte", joined))
-
-    # Format list of affected classes
-    if info.affected_classes:
-        joined = ", ".join(sorted([x.name for x in info.affected_classes]))
-        info.rows.append(("Betroffene Klassen", joined))
-
-    # Format list of missing teachers (absences)
-    if info.absences:
-        elements = []
-        for absence in info.absences:
-            if absence.type != TYPE_TEACHER:
-                continue
-            if absence.is_whole_day:
-                # Teacher is missing the whole day
-                elements.append("{}".format(absence.teacher.shortcode))
-            elif absence.from_lesson == absence.to_lesson:
-                elements.append("{} ({}.)".format(absence.teacher.shortcode, absence.from_lesson))
-            else:
-                # Teacher is only missing a part of day
-                elements.append(
-                    "{} ({}.-{}.)".format(absence.teacher.shortcode, absence.from_lesson, absence.to_lesson))
-        elements.sort()
-        joined = ", ".join(elements)
-
-        info.rows.append(("Abwesende Lehrkräfte", joined))
-
-    return info
-
-
-def get_substitutions_by_date(date):
-    subs_raw = run_default_filter(
-        run_using(models.Substitution.objects.filter(date=date_to_untis_date(date), deleted=0).exclude(
-            Q(flags__contains="N") |
-            Q(flags__contains="b") |
-            Q(flags__contains="F") |
-            Q(flags__exact="g")).order_by("classids", "lesson")),
-        filter_term=False)
-
-    subs = row_by_row_helper(subs_raw, Substitution)
-    # subs.sort(key=substitutions_sorter)
-    return subs
-
-
-def get_substitutions_by_date_as_dict(date):
-    subs_raw = get_substitutions_by_date(date)
-    sub_table = generate_sub_table(subs_raw)
-    subs = {}
-    for i, sub_raw in enumerate(subs_raw):
-        if sub_raw.lesson_id not in subs.keys():
-            subs[sub_raw.lesson_id] = []
-        sub_row = None
-        for sub_item in sub_table:
-            if sub_item.sub.id == sub_raw.id:
-                sub_row = sub_item
-        subs[sub_raw.lesson_id].append({"sub": sub_raw, "table": sub_row})
-
-    return subs