diff --git a/aleksis/apps/untis/forms.py b/aleksis/apps/untis/forms.py deleted file mode 100644 index 66a2f9d05fc92e1877634c867a695431cd6059e2..0000000000000000000000000000000000000000 --- a/aleksis/apps/untis/forms.py +++ /dev/null @@ -1,6 +0,0 @@ -from django import forms -from django.utils.translation import gettext_lazy as _ - - -class UntisUploadForm(forms.Form): - untis_xml = forms.FileField(label=_("Untis XML export")) diff --git a/aleksis/apps/untis/management/commands/untis_import_xml.py b/aleksis/apps/untis/management/commands/untis_import_xml.py deleted file mode 100644 index efbaa675f26561d2961e856c0251086cb2956263..0000000000000000000000000000000000000000 --- a/aleksis/apps/untis/management/commands/untis_import_xml.py +++ /dev/null @@ -1,14 +0,0 @@ -from django.core.management.base import BaseCommand -from django.utils.translation import ugettext as _ - -from ...util.xml.xml import untis_import_xml - - -class Command(BaseCommand): - def add_arguments(self, parser): - parser.add_argument("untis_xml_path", help=_("Path to Untis XML export file")) - - def handle(self, *args, **options): - untis_xml = open(options["untis_xml_path"], "rb") - - untis_import_xml(None, untis_xml) diff --git a/aleksis/apps/untis/menus.py b/aleksis/apps/untis/menus.py index f05d52f7451d3eb627a57f6f960c8da49de3921e..d9f723ff1ef69c8eb1eca61be17110d12da5cce8 100644 --- a/aleksis/apps/untis/menus.py +++ b/aleksis/apps/untis/menus.py @@ -2,13 +2,6 @@ from django.utils.translation import gettext_lazy as _ MENUS = { "DATA_MANAGEMENT_MENU": [ - { - "name": _("Untis XML import"), - "url": "untis_xml_import", - "validators": [ - ("aleksis.core.util.predicates.permission_validator", "untis.do_xml_import_rule",), - ], - }, { "name": _("Link subjects to groups (for UNTIS MySQL import)"), "url": "untis_groups_subjects", diff --git a/aleksis/apps/untis/migrations/0001_initial.py b/aleksis/apps/untis/migrations/0001_initial.py index dcdd6f43da756851d1ac4f3449132d1634c4349f..befeb5e61c5ef098ec02af3a268ce73f01756b89 100644 --- a/aleksis/apps/untis/migrations/0001_initial.py +++ b/aleksis/apps/untis/migrations/0001_initial.py @@ -2272,7 +2272,6 @@ class Migration(migrations.Migration): ], options={ "permissions": ( - ("do_xml_import", "Can do XML import"), ("assign_subjects_to_groups", "Can assign subjects to groups"), ), "managed": False, diff --git a/aleksis/apps/untis/migrations/0002_auto_20200820_1542.py b/aleksis/apps/untis/migrations/0002_auto_20200820_1542.py index a3d79487be9872fa30e8e36f9ebf1ed2eb6ca310..eef0e28210a53a88217d3825bdb5c72238313d65 100644 --- a/aleksis/apps/untis/migrations/0002_auto_20200820_1542.py +++ b/aleksis/apps/untis/migrations/0002_auto_20200820_1542.py @@ -12,6 +12,6 @@ class Migration(migrations.Migration): operations = [ migrations.AlterModelOptions( name='globalpermissions', - options={'managed': False, 'permissions': (('do_xml_import', 'Kann XML-Import durchführen'), ('assign_subjects_to_groups', 'Kann Fächer zu Gruppen zuzuordnen'))}, + options={'managed': False, 'permissions': (('assign_subjects_to_groups', 'Kann Fächer zu Gruppen zuzuordnen'),)}, ), ] diff --git a/aleksis/apps/untis/models.py b/aleksis/apps/untis/models.py index d14197965dc3839254117b55d2a2ac4bf12bf16f..4d1d23ac62b252e6549f857cb6187452fb1584df 100644 --- a/aleksis/apps/untis/models.py +++ b/aleksis/apps/untis/models.py @@ -4218,7 +4218,4 @@ class Views(models.Model, PureDjangoModel): class GlobalPermissions(models.Model, PureDjangoModel): class Meta: managed = False - permissions = ( - ("do_xml_import", _("Can do XML import")), - ("assign_subjects_to_groups", _("Can assign subjects to groups")), - ) + permissions = (("assign_subjects_to_groups", _("Can assign subjects to groups")),) diff --git a/aleksis/apps/untis/rules.py b/aleksis/apps/untis/rules.py index fc420c375e468c9043993ec1be6a52914c965c9e..cf7b59ca6d5caa9402291a83331925cad96e5372 100644 --- a/aleksis/apps/untis/rules.py +++ b/aleksis/apps/untis/rules.py @@ -2,12 +2,6 @@ from rules import add_perm from aleksis.core.util.predicates import has_global_perm, has_person -# Do XML import -do_xml_import_predicate = has_person & has_global_perm("untis.do_xml_import") -add_perm("untis.do_xml_import_rule", do_xml_import_predicate) - - -# Do XML import assign_subjects_to_groups_predicate = has_person & has_global_perm( "untis.assign_subjects_to_groups" ) diff --git a/aleksis/apps/untis/templates/untis/xml_import.html b/aleksis/apps/untis/templates/untis/xml_import.html deleted file mode 100644 index 48af24b2606d5f7b00c60a4e655257d16c8e4547..0000000000000000000000000000000000000000 --- a/aleksis/apps/untis/templates/untis/xml_import.html +++ /dev/null @@ -1,43 +0,0 @@ -{# -*- engine:django -*- #} - -{% extends "core/base.html" %} - -{% load material_form i18n %} - -{% block browser_title %}{% blocktrans %}Import Untis data via XML{% endblocktrans %}{% endblock %} -{% block page_title %}{% blocktrans %}Import Untis data via XML{% endblocktrans %}{% endblock %} - -{% block content %} - - <p class="flow-text"> - {% blocktrans %} - Untis provides a function for exporting all data as an XML file. - {% endblocktrans %} - </p> - <div class="alert warning"> - <p> - <i class="material-icons left">warning</i> - {% blocktrans %} - Newly imported data will be valid as of tomorrow. - {% endblocktrans %} - {% blocktrans %} - The effective dates of all existing lessons will be set to end - today. - {% endblocktrans %} - {% blocktrans %} - The effective dates of all newly imported lessons will be set to - start tomorrow. - {% endblocktrans %} - {% blocktrans %} - Teachers, rooms, subjects and classes and periods will be updated in place. - {% endblocktrans %} - </p> - </div> - - <form method="post" enctype="multipart/form-data"> - {% csrf_token %} - {% form form=upload_form %}{% endform %} - {% include "core/partials/save_button.html" with icon="import_export" caption=_("Import data") %} - </form> - -{% endblock %} diff --git a/aleksis/apps/untis/urls.py b/aleksis/apps/untis/urls.py deleted file mode 100644 index 1a5119ea3c6195ab915588b2e3fd684891294b0b..0000000000000000000000000000000000000000 --- a/aleksis/apps/untis/urls.py +++ /dev/null @@ -1,7 +0,0 @@ -from django.urls import path - -from . import views - -urlpatterns = [ - path("import/xml/", views.xml_import, name="untis_xml_import"), -] diff --git a/aleksis/apps/untis/util/xml/xml.py b/aleksis/apps/untis/util/xml/xml.py deleted file mode 100644 index 076719b812966962fdf7ffe32a4b2bc6abfda194..0000000000000000000000000000000000000000 --- a/aleksis/apps/untis/util/xml/xml.py +++ /dev/null @@ -1,173 +0,0 @@ -from datetime import date, time, timedelta -from typing import BinaryIO, Optional, Union -from xml.dom import Node - -from django.http import HttpRequest -from django.utils.translation import ugettext as _ - -import defusedxml - -from aleksis.apps.chronos.models import Lesson, Room, Subject, TimePeriod -from aleksis.core.models import Group, Person -from aleksis.core.util import messages - - -def get_child_node_text(node: Node, tag: str) -> Optional[str]: - tag_nodes = node.getElementsByTagName(tag) - - if len(tag_nodes) == 1: - return tag_nodes[0].firstChild.nodeValue - else: - return None - - -def get_child_node_id(node: Node, tag: str) -> Optional[str]: - tag_nodes = node.getElementsByTagName(tag) - - if len(tag_nodes) == 1: - return tag_nodes[0].attributes["id"].value - else: - return None - - -def untis_import_xml(request: HttpRequest, untis_xml: Union[BinaryIO, str]) -> None: - dom = defusedxml.parse(untis_xml) - - subjects = dom.getElementsByTagName("subject") - for subject_node in subjects: - short_name = subject_node.attributes["id"].value[3:] - name = get_child_node_text(subject_node, "longname") - colour_fg = get_child_node_text(subject_node, "forecolor") - colour_bg = get_child_node_text(subject_node, "backcolor") - - Subject.objects.select_related(None).prefetch_related(None).update_or_create( - short_name=short_name, - defaults={"name": name, "colour_fg": colour_fg, "colour_bg": colour_bg}, - ) - - periods = dom.getElementsByTagName("timeperiod") - for period_node in periods: - weekday = int(get_child_node_text(period_node, "day")) - period = int(get_child_node_text(period_node, "period")) - starttime = get_child_node_text(period_node, "starttime") - endtime = get_child_node_text(period_node, "endtime") - - time_start = time(int(starttime[:2]), int(starttime[2:])) - time_end = time(int(endtime[:2]), int(endtime[2:])) - - TimePeriod.objects.select_related(None).prefetch_related(None).update_or_create( - weekday=weekday, - period=period, - defaults={"time_start": time_start, "time_end": time_end}, - ) - - rooms = dom.getElementsByTagName("room") - for room_node in rooms: - short_name = room_node.attributes["id"].value[3:] - name = get_child_node_text(room_node, "longname") - - Room.objects.select_related(None).prefetch_related(None).update_or_create( - short_name=short_name, defaults={"name": name} - ) - - classes = dom.getElementsByTagName("class") - for class_node in classes: - short_name = class_node.attributes["id"].value[3:] - name = _("Class %s") % short_name - class_teacher_short_name = get_child_node_id(class_node, "class_teacher")[3:] - - class_, created = ( - Group.objects.select_related(None) - .prefetch_related(None) - .update_or_create(short_name=short_name, defaults={"name": name}) - ) - - try: - # Teachers need to come from another source, e.g. SchILD-NRW - class_.owners.set([Person.objects.get(short_name=class_teacher_short_name)]) - class_.save() - except Person.DoesNotExist: - messages.warning( - request, - _("Could not set class teacher of %(class)s to %(teacher)s.") - % {"class": short_name, "teacher": class_teacher_short_name}, - ) - - # Set all existing lessons that overlap to end today - today = date.today() - Lesson.objects.filter(date_end__gt=today).update(date_end=today) - - lessons = dom.getElementsByTagName("lesson") - for lesson_node in lessons: - subject_short_name = get_child_node_id(lesson_node, "lesson_subject")[3:] - teacher_short_name = get_child_node_id(lesson_node, "lesson_teacher")[3:] - group_short_names = [ - v.strip() - for v in get_child_node_id(lesson_node, "lesson_classes").split("CL_") - if v.strip() - ] - effectivebegindate = get_child_node_text(lesson_node, "effectivebegindate") - effectiveenddate = get_child_node_text(lesson_node, "effectiveenddate") - - times = lesson_node.getElementsByTagName("time") - time_periods = [] - for time_node in times: - day = int(get_child_node_text(time_node, "assigned_day")) - period = int(get_child_node_text(time_node, "assigned_period")) - - room_id = get_child_node_id(time_node, "assigned_room") - room = room_id[3:] if room_id else None - - time_periods.append((day, period, room)) - - subject = Subject.objects.get(short_name=subject_short_name) - periods = [ - ( - TimePeriod.objects.get(weekday=v[0], period=v[1]), - Room.objects.get(short_name=v[2]) if v[2] else None, - ) - for v in time_periods - ] - date_start = ( - date( - int(effectivebegindate[:4]), - int(effectivebegindate[4:6]), - int(effectivebegindate[6:]), - ) - if effectivebegindate - else None - ) - date_end = ( - date(int(effectiveenddate[:4]), int(effectiveenddate[4:6]), int(effectiveenddate[6:]),) - if effectiveenddate - else None - ) - - # Coerce effective start date to not be before tomorrow - if date_start and date_start <= today: - date_start = today + timedelta(days=1) - - try: - groups = [Group.objects.get(short_name=v) for v in group_short_names] - except Group.DoesNotExist: - messages.error(request, _("Invalid list of classes: %s") % ", ".join(group_short_names)) - continue - - try: - teachers = [Person.objects.get(short_name=teacher_short_name)] - except Person.DoesNotExist: - messages.error( - request, - _("Failed to import lesson: Teacher %s does not exist.") % teacher_short_name, - ) - continue - - lesson = Lesson.objects.create(subject=subject, date_start=date_start, date_end=date_end) - - lesson.groups.set(groups) - lesson.teachers.set(teachers) - - for period in periods: - lesson.periods.add(period[0], through_defaults={"room": period[1]}) - - lesson.save() diff --git a/aleksis/apps/untis/views.py b/aleksis/apps/untis/views.py deleted file mode 100644 index 84b2a2d8b2505ef04d4a528b627b05e8eddbd3c2..0000000000000000000000000000000000000000 --- a/aleksis/apps/untis/views.py +++ /dev/null @@ -1,24 +0,0 @@ -from django.http import HttpRequest, HttpResponse -from django.shortcuts import render - -from rules.contrib.views import permission_required - -from .forms import UntisUploadForm -from .util.xml.xml import untis_import_xml - - -@permission_required("untis.do_xml_import_rule") -def xml_import(request: HttpRequest) -> HttpResponse: - context = {} - - upload_form = UntisUploadForm() - - if request.method == "POST": - upload_form = UntisUploadForm(request.POST, request.FILES) - - if upload_form.is_valid(): - untis_import_xml(request, request.FILES["untis_xml"]) - - context["upload_form"] = upload_form - - return render(request, "untis/xml_import.html", context)