Release - Upload

This commit is contained in:
Js_Sman_Omen committed 2025-03-24 14:34:56 +01:00
commit 89f35ca466
370 files changed
+32904

No files matched your search

+54
View File
@@ -0,0 +1,54 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Run and Debug Django Backend",
"type": "debugpy",
"request": "launch",
"program": "${workspaceFolder}/backend/manage.py",
"args": [
"runserver",
"127.0.0.1:8000"
],
"django": true,
"autoStartBrowser": true,
"cwd": "${workspaceFolder}/backend",
"console": "integratedTerminal"
},
{
"name": "Debug React Frontend",
"type": "firefox",
"request": "launch",
"reAttach": true,
"url": "http://localhost:5173",
"webRoot": "${workspaceFolder}/Frontend",
// "runtimeExecutable": "yarn",
// "args": ["dev"],
// "cwd": "${workspaceFolder}/frontend",
// "console": "integratedTerminal"
},
{
"name": "Run React Frontend",
"type": "node",
"request": "launch",
"runtimeExecutable": "yarn",
"args": ["dev"],
"cwd": "${workspaceFolder}/frontend",
"console": "integratedTerminal"
}
],
"compounds": [
{
"name": "Start Django and React",
"configurations": [
"Run and Debug Django Backend",
"Run React Frontend"
]
}
]
}
+168
View File
@@ -0,0 +1,168 @@
# Created by .ignore support plugin (hsz.mobi)
### Python template
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
.DS_Store
# Distribution / packaging
.Python
env/
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
*.egg-info/
.installed.cfg
*.egg
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*,cover
.hypothesis/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# IPython Notebook
.ipynb_checkpoints
# pyenv
.python-version
# celery beat schedule file
celerybeat-schedule
# dotenv
.env
# virtualenv
venv/
ENV/
# Spyder project settings
.spyderproject
# Rope project settings
.ropeproject
### VirtualEnv template
# Virtualenv
# http://iamzed.com/2009/05/07/a-primer-on-virtualenv/
.Python
[Bb]in
[Ii]nclude
[Ll]ib
[Ll]ib64
[Ll]ocal
[Ss]cripts
pyvenv.cfg
.venv
pip-selfcheck.json
### JetBrains template
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
# User-specific stuff:
.idea/workspace.xml
.idea/tasks.xml
.idea/dictionaries
.idea/vcs.xml
.idea/jsLibraryMappings.xml
# Sensitive or high-churn files:
.idea/dataSources.ids
.idea/dataSources.xml
.idea/dataSources.local.xml
.idea/sqlDataSources.xml
.idea/dynamic.xml
.idea/uiDesigner.xml
# Gradle:
.idea/gradle.xml
.idea/libraries
# Mongo Explorer plugin:
.idea/mongoSettings.xml
.idea/
## File-based project format:
*.iws
## Plugin-specific files:
# IntelliJ
/out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
# DB
db.sqlite3
# StudData
studis/xlsmodel/data/
# Logdateien
log/
# Medien
media/
# VSCode
.vscode/launch.json
+20
View File
@@ -0,0 +1,20 @@
{
"workbench.colorCustomizations": {
// Top-Bar
"titleBar.border": "#004F59", // Teal border
"titleBar.activeForeground": "#E0FFFF", // Light cyan text (sky blue feel)
"titleBar.activeBackground": "#007A91", // Vibrant teal background
// Left-Bar
"activityBar.border": "#004F59", // Teal border
"activityBar.activeForeground": "#E0FFFF", // Light cyan active icon
"activityBar.activeBackground": "#00A2C3", // Sky blue for active background
"activityBar.background": "#005F6B", // Deeper teal for overall background
// Bottom-Bar
"statusBar.background": "#004F59", // Teal background
"statusBar.foreground": "#E0FFFF", // Light cyan text
},
"debug.allowBreakpointsEverywhere": false
}
+64
View File
@@ -0,0 +1,64 @@
# Prüfplanviewer
## Installation
Nach dem laden des Repos und der Installation der Module
aus <code> requirements.txt </code> sollten noch folgende
<code> manage.py tasks </code> ausgeführt werden:
- <code> migrate </code> (Anlegen der Datenbanktabellen)
- Befehl aus READ.ME im Verzeichnis <code> fixtures </code>.
Dadurch werden Berechtigungsgruppen angelegt.
Für den Prüfungsplan wird aktuell nur die
Gruppe <code> PP_ADMIN </code> benötigt.
- <code> createsuperuser </code> (Anlage eines ersten Admin-Users)
Danach kann die Anwendung gestartet werden. Anmeldung mit dem
gerade generierten Superuser. Im Bereich "Administration" können
weitere User angelegt werden und ggf. der Gruppe <code> PP_ADMIN </code>
zugeordnet werden. Benutzer in dieser Gruppe können den
Prüfplan nicht nur sehen, sondern auch neue Daten laden.
## Daten
Die Daten werden von Prof. Mahr und Prof. Hopf generiert.
Bei Bedarf müssen wird dort nachfragen. Alte Daten gibt es
auch bei Prof. Hofmann.
## Neue Anforderungen
Nach dem Testbetrieb wurden einige neue Amforderungen
identifiziert:
- Anzeige von "Präsenz"-Pflicht in der
Dozentensicht (ob und wie dies in den Daten
enthalten ist, muss noch geklärt werden)
- Anzeige von "Pendler"-Eigenschaft in der
Dozentensicht (ob und wie dies in den Daten
enthalten ist, muss noch geklärt werden)
- Anzeige von ungeplanten Prüfungen
(also z.B. alternative Prüfungsformen während COVID)
(ob und wie dies in den Daten
enthalten ist, muss noch geklärt werden)
- Anzeige des Versionsstands der importierten Daten
(ob und wie dies in den Daten
enthalten ist, muss noch geklärt werden)
- Import der Daten auch von Kommandozeile
(nicht nur über Web-Upload)
- iCal-Export von Prüfungen
zum Import in den Kalender
- bei der Detailansicht einer Prüfung sollen
alle Prüfer, Räume und die jeweilig Anzahl
der Studierenden angezeigt werden.
(ob und wie dies in den Daten
enthalten ist, muss noch geklärt werden)
- Bessere Anzeige auf mobilen Geräten (responsive)
## ToDOs
- Klären der Datenschnittstelle
- Überarbeiten des Datenimports (neue Daten, Kommandozeile)
- Erweitern der Anzeige
* entweder in der bestehenden App
* oder in einer Single-Page-App
* oder beides
View File
Whitespace-only changes.
View File
Whitespace-only changes.
+576
View File
@@ -0,0 +1,576 @@
import datetime
import inspect
import json
from rest_framework import serializers
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
from pruefplan_parser.models import JsonParser
from pruefplan_viewer.models import *
# from django.utils.encoding import smart_str
# Class to generate a UserToken with custom fields
class MyTokenObtainPairSerializer(TokenObtainPairSerializer):
@classmethod
def get_token(cls, user):
token = super().get_token(user) # Default Token
# Add custom informations to the Token
token["username"] = user.username
token["password"] = user.password
return token
class API_ExamDataSet_ForStudentSerializer(serializers.ModelSerializer):
class Meta:
model = API_ExamDataSet_ForStudent
fields = '__all__'
class PruefPlan_JSON_Serializer(serializers.Serializer):
def create(self, validated_data):
return super().create(validated_data)
def validate(self, data):
if "array" not in data or not isinstance(data["array"], list):
raise serializers.ValidationError(
"Das 'array'-Feld ist erforderlich und muss als Python-Liste verfügbar sein."
)
return {"dataArray": data["array"]} # Rückgabe des validierten Datenarrays
class Lecturer_JSON_Serializer(serializers.Serializer):
# Definiert die Felder, die der Serializer erwartet
revision = serializers.CharField(required=True)
array = serializers.ListField()
def create(self, validated_data):
# Definieren der erwarteten Schlüssel im JSON-Daten
idKey = "kennung"
firstNameKey = "vorname"
lastNameKey = "nachname"
titleKey = "titel"
created_lecturers = [] # Liste zum Speichern der erstellten Lecturer-Objekte
try:
# Schleife über die Daten, um Lecturer-Objekte zu erstellen
for iteration_number, d in enumerate(validated_data["dataArray"]):
# Lecturer-Objekt erstellen und speichern
entry = Lecturer(
identification=d[idKey],
firstName=d[firstNameKey],
lastName=d[lastNameKey],
title=d[titleKey],
)
entry.save()
created_lecturers.append(entry) # Objekt der Liste hinzufügen
except KeyError as e:
# Fehlerbehandlung bei fehlenden Schlüsseln
calling_function = inspect.stack()[0][3]
template = "Exception of type [{0}] occurred in function {1} in iteration {2} of the loop.. Arguments: {3!r}. Message: [{4}] entry might be missing"
message = template.format(
type(e).__name__,
calling_function,
iteration_number,
e.args,
e,
)
JsonParser.exceptionMessages.append(message) # Fehlermeldung speichern
except Exception as e:
# Allgemeine Fehlerbehandlung
calling_function = inspect.stack()[0][3]
template = "Exception of type [{0}] occurred in function {1} in iteration {2} of the loop. Arguments: {3!r}. Message: {4}."
message = template.format(
type(e).__name__,
calling_function,
iteration_number,
e.args,
e.__str__(),
)
JsonParser.exceptionMessages.append(message) # Fehlermeldung speichern
return {
"Serializer": "Lecturer",
"status": "success",
"created_count": len(created_lecturers),
} # Rückgabe des Erfolgsstatus
def validate(self, data):
# Validierung, um sicherzustellen, dass 'revision' und 'array' Felder vorhanden sind
if "revision" not in data.keys():
raise serializers.ValidationError("Das 'revision'-Feld ist erforderlich.")
if "array" not in data or not isinstance(data["array"], list):
raise serializers.ValidationError(
"Das 'array'-Feld ist erforderlich und muss als Python-Liste verfügbar sein."
)
return {"dataArray": data["array"]} # Rückgabe des validierten Datenarrays
class Attendance_JSON_Serializer(serializers.Serializer):
# Definiert die Felder, die der Serializer erwartet
revision = serializers.CharField(required=True)
array = serializers.ListField()
def create(self, validated_data):
# Definieren der erwarteten Schlüssel im JSON-Daten
idKey = "dozentenkennung"
yearKey = "jahr"
monthKey = "monat"
dayKey = "tag"
hourKey = "stunde"
minuteKey = "minute"
weekdayKey = "wochentag"
dateKey = "termin"
created_attendences = (
[]
) # Liste zum Speichern der erstellten Attendance-Objekte
try:
# Schleife über die Daten, um Attendance-Objekte zu erstellen
for iteration_number, d in enumerate(validated_data["dataArray"]):
# Überprüfung, ob das 'termin'-Feld vorhanden ist
keyAvailable = "termin" in d
if not keyAvailable:
# Warnung ausgeben, wenn kein Termin zugewiesen wurde
template = "Warning. Following Exam was not assigned any examination date ['termin']: [{1}]"
message = template.format(d[idKey])
JsonParser.warningMessages.append(message)
continue
# Datum und Uhrzeit aus den Daten extrahieren
date = datetime.date(
d[dateKey][yearKey], d[dateKey][monthKey], d[dateKey][dayKey]
)
time = datetime.time(d[dateKey][hourKey], d[dateKey][minuteKey])
# Attendance-Objekt erstellen und speichern
entry = Attendance(
identification=d[idKey],
time=time,
date=date,
dateTimeText=d[dateKey]["datumText"],
weekday=d[dateKey]["wochentag"],
)
entry.save()
created_attendences.append(entry) # Objekt der Liste hinzufügen
try:
# Dozent aus der Datenbank abrufen und mit der Anwesenheit verknüpfen
lecturer = Lecturer.objects.get(identification=d[idKey])
lecturer.attendance_set.add(
entry
) # Attendance dem Lecturer zuweisen
except Exception as e:
# Fehlerbehandlung, wenn der Dozent nicht gefunden wird
template = "Exception of type [{0}]. Arguments: {1!r}. Message: [{2}] entry might be missing"
message = template.format(type(e).__name__, e.args, idKey)
JsonParser.exceptionMessages.append(
message
) # Fehlermeldung speichern
except KeyError as e:
# Fehlerbehandlung bei fehlenden Schlüsseln
calling_function = inspect.stack()[0][3]
template = "Exception of type [{0}] occurred in function {1} in iteration {2} of the loop.. Arguments: {3!r}. Message: [{4}] entry might be missing"
message = template.format(
type(e).__name__,
calling_function,
iteration_number,
e.args,
e,
)
JsonParser.exceptionMessages.append(message) # Fehlermeldung speichern
except Exception as e:
# Allgemeine Fehlerbehandlung
calling_function = inspect.stack()[0][3]
template = "Exception of type [{0}] occurred in function {1} in iteration {2} of the loop. Arguments: {3!r}. Message: {4}."
message = template.format(
type(e).__name__,
calling_function,
iteration_number,
e.args,
e.__str__(),
)
JsonParser.exceptionMessages.append(message) # Fehlermeldung speichern
return {
"Serializer": "Attendance",
"status": "success",
"created_count": len(created_attendences),
} # Rückgabe des Erfolgsstatus
def validate(self, data):
# Validierung, um sicherzustellen, dass 'revision' und 'array' Felder vorhanden sind
if "revision" not in data.keys():
raise serializers.ValidationError("Das 'revision'-Feld ist erforderlich.")
if "array" not in data or not isinstance(data["array"], list):
raise serializers.ValidationError(
"Das 'array'-Feld ist erforderlich und muss als Python-Liste verfügbar sein."
)
return {"dataArray": data["array"]} # Rückgabe des validierten Datenarrays
class Subject_JSON_Serializer(serializers.Serializer):
# Definiert die Felder, die der Serializer erwartet
revision = serializers.CharField(required=True)
array = serializers.ListField()
def create(self, validated_data):
# Definieren der erwarteten Schlüssel im JSON-Daten
idKey = "kennung"
initialsKey = "kurztext"
nameKey = "langtext"
ohmIdKey = "fachkennungOhm"
created_subjects = [] # Liste zum Speichern der erstellten Subject-Objekte
try:
# Schleife über die Daten, um Subject-Objekte zu erstellen
for iteration_number, d in enumerate(validated_data["dataArray"]):
# Subject-Objekt erstellen und speichern
entry = Subject(
identification=d[idKey],
initials=d[ohmIdKey][initialsKey],
name=d[ohmIdKey][nameKey],
)
entry.save()
created_subjects.append(entry) # Objekt der Liste hinzufügen
except KeyError as e:
# Fehlerbehandlung bei fehlenden Schlüsseln
calling_function = inspect.stack()[0][3]
template = "Exception of type [{0}] occurred in function {1} in iteration {2} of the loop.. Arguments: {3!r}. Message: [{4}] entry might be missing"
message = template.format(
type(e).__name__,
calling_function,
iteration_number,
e.args,
e,
)
JsonParser.exceptionMessages.append(message) # Fehlermeldung speichern
except Exception as e:
# Allgemeine Fehlerbehandlung
calling_function = inspect.stack()[0][3]
template = "Exception of type [{0}] occurred in function {1} in iteration {2} of the loop. Arguments: {3!r}. Message: {4}."
message = template.format(
type(e).__name__,
calling_function,
iteration_number,
e.args,
e.__str__(),
)
JsonParser.exceptionMessages.append(message) # Fehlermeldung speichern
return {
"Serializer": "Subject",
"status": "success",
"created_count": len(created_subjects),
} # Rückgabe des Erfolgsstatus
def validate(self, data):
# Validierung, um sicherzustellen, dass 'revision' und 'array' Felder vorhanden sind
if "revision" not in data.keys():
raise serializers.ValidationError("Das 'revision'-Feld ist erforderlich.")
if "array" not in data or not isinstance(data["array"], list):
raise serializers.ValidationError(
"Das 'array'-Feld ist erforderlich und muss als Python-Liste verfügbar sein."
)
return {"dataArray": data["array"]} # Rückgabe des validierten Datenarrays
class Exam_JSON_Serializer(serializers.Serializer):
# Define the fields expected by the serializer
revision = serializers.CharField(required=True)
array = serializers.ListField()
def create(self, validated_data):
# Define the expected keys in the JSON data
idKey = "kennung"
yearKey = "jahr"
monthKey = "monat"
dayKey = "tag"
hourKey = "stunde"
minuteKey = "minute"
weekdayKey = "wochentag"
dateKey = "termin"
partialExamsKey = "teilpruefungen"
partialExamIdKey = "kennung"
numRegStudKey = "anzahlAnmeldungen"
subjectIdsKey = "fachkennungen"
examExecutionsKey = "pruefungsdurchfuehrungen"
lecturerIdKey = "dozentenkennung"
supervisorTypeKey = "typ"
locationKey = "raum"
created_exams = [] # List to store created Exam objects
created_partialexams = [] # List to store created Exam objects
ignored_Vorgezogen_exams = 0 # List to ignored Exam objects
ignored_KeinTermin_exams = 0 # List to ignored Exam objects
try:
# Iterate over the data to create Exam objects
for iteration_number, d in enumerate(validated_data["dataArray"]):
# Certain exam entries are ignored
if d["pruefungsart"] == "LN_VORGEZOGEN": # These entries can be ignored
ignored_Vorgezogen_exams += 1
continue
keyAvailable = "termin" in d
if not keyAvailable:
# Warning if no examination date is assigned
template = "Warning. Following Exam was not assigned any examination date ['termin']: [{0}]"
message = template.format(d[idKey])
JsonParser.warningMessages.append(message)
ignored_KeinTermin_exams += 1
continue
# Extract date and time for the exam
date = datetime.date(
d[dateKey][yearKey], d[dateKey][monthKey], d[dateKey][dayKey]
)
time = datetime.time(d[dateKey][hourKey], d[dateKey][minuteKey])
# Create and save a new Exam entry
examEntry = Exam(
identification=d[idKey],
date=date,
time=time,
weekday=d[dateKey][weekdayKey],
)
examEntry.save()
created_exams.append(examEntry)
# Create PartialExam entries and link them with the main exam
for teilpruef in d[partialExamsKey]:
partialExamId = teilpruef[partialExamIdKey]
regStudCount = teilpruef[numRegStudKey]
# Create and save a new PartialExam entry
partialExam = PartialExam(
identification=partialExamId, regStudCount=regStudCount
)
partialExam.save()
created_partialexams.append(partialExam)
# Link Exam and PartialExam (One-to-Many relationship)
examEntry.partialexam_set.add(partialExam)
# Link subjects to the PartialExams
for subId in teilpruef[subjectIdsKey]:
try:
# Check if the subject exists and link it
subject = Subject.objects.get(identification=subId)
partialExam.subjectIds.add(
subject
) # Many-to-Many relationship
except Exception as e:
# Log an error if the subject is not found
template = "Exception of type [{0}]. Arguments: {1!r}. Message: [{2}] entry might be missing"
message = template.format(type(e).__name__, e.args, subId)
JsonParser.exceptionMessages.append(message)
# Link exam executions to PartialExams
for pruefdurch in teilpruef[examExecutionsKey]:
lecId = pruefdurch[lecturerIdKey]
supervisorType = pruefdurch[supervisorTypeKey]
location = pruefdurch[locationKey]
# Create and save a new ExamExecution entry
examExecution = ExamExecution(
supervisorType=supervisorType, location=location
)
examExecution.save()
# Check if the lecturer exists and link the exam execution
try:
lecturer = Lecturer.objects.get(pk=lecId)
lecturer.examexecution_set.add(
examExecution
) # One-to-Many relationship
except Exception as e:
# Log an error if the lecturer is not found
template = "Exception of type [{0}]. Arguments: {1!r}. Message: [{2}] entry might be missing"
message = template.format(type(e).__name__, e.args, lecId)
JsonParser.exceptionMessages.append(message)
# Link subjects to the ExamExecution
for subId in pruefdurch[subjectIdsKey]:
try:
# Check if the subject exists and link it
subject = Subject.objects.get(identification=subId)
examExecution.subjectIds.add(
subject
) # Many-to-Many relationship
except Exception as e:
# Log an error if the subject is not found
template = "Exception of type [{0}]. Arguments: {1!r}. Message: [{2}] entry might be missing"
message = template.format(
type(e).__name__, e.args, subId
)
JsonParser.exceptionMessages.append(message)
# Link PartialExam and ExamExecution (One-to-Many relationship)
partialExam.examexecution_set.add(examExecution)
except KeyError as e:
# Error handling for missing keys in the dict
calling_function = inspect.stack()[0][3]
template = "Exception of type [{0}] occurred in function {1} in iteration {2} of the loop.. Arguments: {3!r}. Message: [{4}] entry might be missing"
message = template.format(
type(e).__name__,
calling_function,
iteration_number,
e.args,
e,
)
JsonParser.exceptionMessages.append(message)
except Exception as e:
# General error handling
calling_function = inspect.stack()[0][3]
template = "Exception of type [{0}] occurred in function {1} in iteration {2} of the loop. Arguments: {3!r}. Message: {4}."
message = template.format(
type(e).__name__,
calling_function,
iteration_number,
e.args,
e.__str__(),
)
JsonParser.exceptionMessages.append(message)
return {
"Serializer": "Exam",
"status": "success",
"created_Exams": len(created_exams),
"created_PartialExams_count": len(created_partialexams),
"ignored_Exams -> Vorgezogen": ignored_Vorgezogen_exams,
"ignored_Exams -> Kein Termin": ignored_KeinTermin_exams,
}
def validate(self, data):
# Validation for the 'revision' field
if "revision" not in data.keys():
raise serializers.ValidationError("The 'revision' field is required.")
# Validation for the 'array' field
if "array" not in data or not isinstance(data["array"], list):
raise serializers.ValidationError(
"The 'array' field is required and must be a Python list."
)
return {"dataArray": data["array"]}
class RoomAllocation_JSON_Serializer(serializers.Serializer):
# Define the fields expected by the serializer
revision = serializers.CharField(required=True)
array = serializers.ListField()
def create(self, validated_data):
# Define the expected keys in the JSON data
idKey = "kennungPruefung"
yearKey = "jahr"
monthKey = "monat"
dayKey = "tag"
hourKey = "stunde"
minuteKey = "minute"
weekdayKey = "wochentag"
locationKey = "raum"
dateKey = "termin"
matrikelKey = "matrikel"
created_roomAllocations = [] # List to store created StudentExam objects
try:
# Iterate over the data to create StudentExam objects
for iteration_number, d in enumerate(validated_data["dataArray"]):
# Extract date and time
date = datetime.date(
d[dateKey][yearKey], d[dateKey][monthKey], d[dateKey][dayKey]
)
time = datetime.time(d[dateKey][hourKey], d[dateKey][minuteKey])
# Find the corresponding Exam entry
exam = Exam.objects.filter(
identification=d[idKey], date=date, time=time
).first()
# Iterate through partial exams and their executions
partialExams = exam.partialexam_set.all()
for partialExam in partialExams:
examExecutions = partialExam.examexecution_set.all()
for examExecution in examExecutions:
# Check if the location matches and create StudentExam entry
if examExecution.location == d[locationKey]:
studentExamEntry = StudentExam(
examIdentification=d[idKey],
date=date,
time=time,
weekday=d[dateKey][weekdayKey],
location=d[locationKey],
examExecution=examExecution,
)
studentExamEntry.save()
created_roomAllocations.append(studentExamEntry)
# Create or update Student entries
for matrikel in d[matrikelKey]:
studentEntry = Student.objects.filter(matrikel=matrikel).exists()
if not studentEntry:
# Create a new Student entry if it doesn't exist
entry = Student(matrikel=matrikel)
entry.save()
else:
entry = Student.objects.all().filter(matrikel=matrikel).first()
entry.exams.add(studentExamEntry)
except KeyError as e:
# Error handling for missing keys in the dict
calling_function = inspect.stack()[0][3]
template = "Exception of type [{0}] occurred in function {1} in iteration {2} of the loop.. Arguments: {3!r}. Message: [{4}] entry might be missing"
message = template.format(
type(e).__name__,
calling_function,
iteration_number,
e.args,
e,
)
JsonParser.exceptionMessages.append(message)
except Exception as e:
# General error handling
calling_function = inspect.stack()[0][3]
template = "Exception of type [{0}] occurred in function {1} in iteration {2} of the loop. Arguments: {3!r}. Message: {4}."
message = template.format(
type(e).__name__,
calling_function,
iteration_number,
e.args,
e.__str__(),
)
JsonParser.exceptionMessages.append(message)
return {
"Serializer": "RoomAllocation",
"status": "success",
"created_RoomAllocations": len(created_roomAllocations),
}
def validate(self, data):
# Validation for the 'revision' field
if "revision" not in data.keys():
raise serializers.ValidationError("The 'revision' field is required.")
# Validation for the 'array' field
if "array" not in data or not isinstance(data["array"], list):
raise serializers.ValidationError(
"The 'array' field is required and must be a Python list."
)
return {"dataArray": data["array"]}
+24
View File
@@ -0,0 +1,24 @@
from django.urls import path
from . import views
from rest_framework_simplejwt.views import TokenRefreshView
from rest_framework.authtoken.views import obtain_auth_token
urlpatterns = [
path(
"user/token",
views.MyTokenObtainPairView.as_view(),
), # URL to classview fpr token interactions "as_view()"
path(
"user/token/refresh/", TokenRefreshView.as_view()
), # Lib view from rest_framework to refresh the given token
path("user/logoutUser", views.logoutUser),
path("user/checkUser", views.checkLoginStatus),
path("fetchExamData", views.getAPI_ExamDataSet_ForStudent),
path("pruefplanUpload/", views.PruefPlanUploader.as_view()),
path("api-token-auth/", obtain_auth_token),
path("addlecturer", views.addLecturer),
path("addAttendance", views.addAttendance),
path("addSubject", views.addSubject),
path("addExam", views.addExam),
path("addRoomAllocation", views.addRoomAllocation),
]
+250
View File
@@ -0,0 +1,250 @@
from datetime import date
import time
from rest_framework.response import Response
from rest_framework.decorators import api_view
from rest_framework.views import APIView
from rest_framework.permissions import IsAuthenticated
from pruefplan_viewer.models import *
from .serializer import *
from django.contrib.auth import authenticate, login, logout
from django.shortcuts import render
from api import serializer as api_serializer
from rest_framework_simplejwt.views import TokenObtainPairView
from django.contrib.auth.models import User
from django.contrib.auth.decorators import login_required
from django.utils.encoding import force_str
# Create a REST API view class to interact with the custom token serializer class
class MyTokenObtainPairView(TokenObtainPairView):
# Setup the serializer -> using custom serializer
serializer_class = api_serializer.MyTokenObtainPairSerializer
# Func to handle a post request on this API endpoint
def post(self, request, *args, **kwargs):
username = request.data.get("username")
password = request.data.get("password")
# User authentication using LADP agains the TH-Server -> Setup LADP in settings.py
user = authenticate(username=username, password=password)
if not user:
return Response({"error": "Invalid credentials"}, status=400)
# Login the user for Backend authentication
login(request=request, user=user)
# Delegate the post request to the TokenObptainPairView class
# Executing the standart jwt creation workflow -> using the custom serializer
return super().post(request, *args, **kwargs)
@api_view(["POST"])
def logoutUser(request):
logout(request)
return Response()
# Extract the location key and map it to a URL
def map_location(location_str):
URL_MAP = {
"B": "https://www.th-nuernberg.de/wie-erreichen-sie-uns/anfahrt/b-standort-bahnhofstrasse/",
"F": "https://www.th-nuernberg.de/wie-erreichen-sie-uns/anfahrt/f-standort-auf-aeg/",
"H": "https://www.th-nuernberg.de/wie-erreichen-sie-uns/anfahrt/h-standort-hohfederstrasse/",
"K": "https://www.th-nuernberg.de/wie-erreichen-sie-uns/anfahrt/k-standort-kesslerplatz/",
"NM": "https://www.th-nuernberg.de/wie-erreichen-sie-uns/anfahrt/nm-standort-neumarkt-in-der-oberpfalz/",
"SC": "https://www.th-nuernberg.de/wie-erreichen-sie-uns/anfahrt/sc-standort-innere-cramer-klett-strasse/",
"SG": "https://www.th-nuernberg.de/wie-erreichen-sie-uns/anfahrt/sg-standort-karl-grillenberger-strasse/",
"SK": "https://www.th-nuernberg.de/wie-erreichen-sie-uns/anfahrt/sk-standort-prof-ernst-nathan-strasse/",
"SP": "https://www.th-nuernberg.de/wie-erreichen-sie-uns/anfahrt/sp-standort-kesslerstrasse/",
"SR": "https://www.th-nuernberg.de/wie-erreichen-sie-uns/anfahrt/sr-standort-rednitzhembach/",
"W": "https://www.th-nuernberg.de/wie-erreichen-sie-uns/anfahrt/w-standort-wassertorstrasse/",
"OL": "Online",
"MC": "https://www.th-nuernberg.de/wie-erreichen-sie-uns/anfahrt/pruefungsstandort-mensa-insel-schuett/",
"Default": "https://www.th-nuernberg.de/wie-erreichen-sie-uns/anfahrt/",
}
if not location_str:
return URL_MAP["Default"] # Fallback URL if location is empty or None
location_key = location_str.split(".")[0] # Get the first part before '.'
# Find the matching key
for key in URL_MAP.keys():
if location_key.startswith(key):
return URL_MAP[key]
return URL_MAP["Default"] # If no match is found, return the default URL
def get_Subject(exam):
partialExam = PartialExam.objects.filter(identification=exam).first()
subjects = partialExam.subjectIds
result = [subject.name for subject in subjects]
pass
class PruefPlanUploader(APIView):
permission_classes = (IsAuthenticated,)
def post(self, request):
timeStart = time.perf_counter()
JsonParser().clearTable()
dataSets = [dataSet for dataSet in request.data]
serializers = [
Lecturer_JSON_Serializer(data=dataSets[0]),
Attendance_JSON_Serializer(data=dataSets[1]),
Subject_JSON_Serializer(data=dataSets[2]),
Exam_JSON_Serializer(data=dataSets[3]),
RoomAllocation_JSON_Serializer(data=dataSets[4]),
]
respondList = [
serializer.save() for serializer in serializers if serializer.is_valid()
]
partial_delta = generate_ExamDataSet_ForStudent()
timeEnd = time.perf_counter()
total_delta = timeEnd - timeStart
respondList.append({"Uploadtime_in_Sekonds": {round(total_delta, ndigits=2)}})
respondList.append({"ExamDataSettime_in_Sekonds": {round(partial_delta, ndigits=2)}})
return Response(respondList)
@api_view(["GET"])
def getAPI_ExamDataSet_ForStudent(request):
exam_data = API_ExamDataSet_ForStudent.objects.all()
# Serialize the data using the ModelSerializer
serializer = API_ExamDataSet_ForStudentSerializer(exam_data, many=True)
return Response(serializer.data) # This will return the data as JSON
@api_view(["POST"])
def pruefplanUpload(request):
timeStart = time.perf_counter()
dataSets = [dataSet for dataSet in request.data]
serializers = [
Lecturer_JSON_Serializer(data=dataSets[0]),
Attendance_JSON_Serializer(data=dataSets[1]),
Subject_JSON_Serializer(data=dataSets[2]),
Exam_JSON_Serializer(data=dataSets[3]),
RoomAllocation_JSON_Serializer(data=dataSets[4]),
]
respondList = [
serializer.save() for serializer in serializers if serializer.is_valid()
]
generate_ExamDataSet_ForStudent()
timeEnd = time.perf_counter()
delta = timeEnd - timeStart
print(f"Time for Upload: {round(delta)}s")
respondList.append(delta)
return Response(respondList)
def generate_ExamDataSet_ForStudent():
timeStart = time.perf_counter()
students = Student.objects.all()
for student in students:
for studentExam in student.exams.all():
examDataSet_ForStudent = API_ExamDataSet_ForStudent(
date=studentExam.date,
time=studentExam.time,
weekday=studentExam.weekday,
room=studentExam.location,
location=map_location(studentExam.location),
subjectIdent=list(
{
subject.name
for subject in studentExam.examExecution.partialExam.subjectIds.all()
}
)[0],
examIdent=studentExam.examIdentification,
examStudCount=studentExam.examExecution.partialExam.regStudCount,
supervisor=f"{studentExam.examExecution.lecturer.firstName} {studentExam.examExecution.lecturer.lastName}",
studMartNr=student.matrikel,
)
examDataSet_ForStudent.save()
timeEnd = time.perf_counter()
delta = timeEnd - timeStart
return delta
@api_view(["POST"])
def checkLoginStatus(request):
username = request.data["username"]
if User.objects.filter(username=username).exists():
usr = User.objects.get(username=username)
if usr.is_authenticated:
return Response(data="IsLoggedin")
else:
return Response(data="IsNotLoggedin")
else:
return Response(data="No user exist with this {} username.".format(username))
@api_view(["POST"])
def addLecturer(request):
serializer = Lecturer_JSON_Serializer(data=request.data)
if serializer.is_valid():
Lecturer_JASON_Serializer_Respond = (
serializer.save()
) # Hier wird der Rückgabewert von create() erfasst
# Erstelle eine Response basierend auf den erstellten Lecturer-Objekten
return Response(Lecturer_JASON_Serializer_Respond)
@api_view(["POST"])
def addAttendance(request):
serializer = Attendance_JSON_Serializer(data=request.data)
if serializer.is_valid():
Attendance_JSON_Serializer_Respond = (
serializer.save()
) # Hier wird der Rückgabewert von create() erfasst
# Erstelle eine Response basierend auf den erstellten Lecturer-Objekten
return Response(Attendance_JSON_Serializer_Respond)
@api_view(["POST"])
def addSubject(request):
serializer = Subject_JSON_Serializer(data=request.data)
if serializer.is_valid():
Subject_JASON_Serializer_Respond = (
serializer.save()
) # Hier wird der Rückgabewert von create() erfasst
# Erstelle eine Response basierend auf den erstellten Lecturer-Objekten
return Response(Subject_JASON_Serializer_Respond)
@api_view(["POST"])
def addExam(request):
serializer = Exam_JSON_Serializer(data=request.data)
if serializer.is_valid():
Exam_JASON_Serializer_Respond = (
serializer.save()
) # Hier wird der Rückgabewert von create() erfasst
# Erstelle eine Response basierend auf den erstellten Lecturer-Objekten
return Response(Exam_JASON_Serializer_Respond)
@api_view(["POST"])
def addRoomAllocation(request):
serializer = RoomAllocation_JSON_Serializer(data=request.data)
if serializer.is_valid():
RoomAllocation_JASON_Serializer_Respond = (
serializer.save()
) # Hier wird der Rückgabewert von create() erfasst
# Erstelle eine Response basierend auf den erstellten Lecturer-Objekten
return Response(RoomAllocation_JASON_Serializer_Respond)
View File
Whitespace-only changes.
+3
View File
@@ -0,0 +1,3 @@
from django.contrib import admin
# Register your models here.
+5
View File
@@ -0,0 +1,5 @@
from django.apps import AppConfig
class AuthStuffConfig(AppConfig):
name = 'authstuff'
+167
View File
@@ -0,0 +1,167 @@
import logging
import datetime
import pytz
import string
import threading
import time
from ldap3 import Server, Connection, ALL, NTLM, ALL_ATTRIBUTES
from django.core.exceptions import ValidationError
from django.utils import timezone
from authstuff.models import ActiveDirectoryEntry
from django.conf import settings
logger = logging.getLogger(__name__)
LOGIN_FIELD = "sAMAccountName"
EXPIRE_FIELD = "accountExpires"
DEPARTMENT_FIELD = "department"
GIVENNAME_FIELD = "givenName"
LASTNAME_FIELD = "sn"
ROLE_FIELD = "description"
class UpdateThread(threading.Thread):
def __init__(self, connection, domain, delta):
super(UpdateThread, self).__init__(group=None)
self.logger = logging.getLogger(__name__)
self.connection = connection
self.domain = domain
self.delta = delta
def run(self):
if has_to_update(self.delta):
try:
startchars = string.ascii_lowercase[:26] + "_"
for char in startchars:
self.logger.info('Update AD entries with leading {}'.format(char))
update_entries_with_leading_char(self.connection, self.domain, char)
time.sleep(5)
except Exception as e:
self.logger.error(str(e))
self.connection.unbind()
def last_update():
result = datetime.datetime.combine(datetime.date.min, datetime.time.min)
try:
entry = ActiveDirectoryEntry.objects.latest('modified')
result = entry.modified
except:
logger.debug('No last update found')
logger.info('Last update: {}'.format(result))
return result
def has_to_update(delta):
deadline = timezone.now() - delta
deadline = deadline.replace(tzinfo=pytz.UTC)
last = last_update().replace(tzinfo=pytz.UTC)
result = settings.LDAP_FORCE_UPDATE or (last < deadline)
logger.info('Has to update: {}'.format(result))
return result
def update_entries(user, pwd, delta):
dom = "ADS1"
conn = get_connection(user, pwd, dom)
update_entries_with_conn(conn, dom, delta)
def update_entries_with_conn(conn, dom, delta):
asyncThread = UpdateThread(conn, dom, delta)
asyncThread.start()
def update_entries_with_leading_char(conn, dom, char):
conn.search(
search_base='OU=users,OU=EFI,OU=Faculties,DC=' + dom + ',DC=fh-nuernberg,DC=de',
search_filter='(&(objectclass=user)(CN=' + char + '*))',
attributes=ALL_ATTRIBUTES)
logger.info('Found {} entries'.format(len(conn.entries)))
for entry in conn.entries:
try:
clear_and_update_entry(entry)
except Exception as e:
logger.error(str(e))
def clear_and_update_entry(entry):
dic = parse_entry_dic(entry)
dic = clear_expire_date(dic)
dic = clear_department(dic)
dic = clear_description(dic)
update_entry(dic)
def update_entry(entry_dic):
login = entry_dic[LOGIN_FIELD]
try:
entry = ActiveDirectoryEntry.objects.get(canonicalName=login)
logger.debug('Update entry {}'.format(login))
except:
logger.debug('New entry {}'.format(login))
entry = ActiveDirectoryEntry()
entry.canonicalName = entry_dic[LOGIN_FIELD]
entry.accountExpires = entry_dic[EXPIRE_FIELD]
entry.department = entry_dic[DEPARTMENT_FIELD]
entry.givenName = entry_dic[GIVENNAME_FIELD]
entry.lastName = entry_dic[LASTNAME_FIELD]
entry.role = entry_dic[ROLE_FIELD]
entry.modified = timezone.now()
logger.debug(entry)
try:
entry.full_clean()
except ValidationError as e:
logger.warning('AD entry not valid: {}'.format(e.message_dict))
entry.save()
def get_connection(user, pwd, dom):
server = Server('gso1.ads1.fh-nuernberg.de', get_info=ALL)
conn = Connection(
server,
user=dom + "\\" + user,
password=pwd,
authentication=NTLM)
conn.bind()
return conn
def parse_entry_dic(entry):
def value_of_field(f):
try:
return entry[f].value
except:
return None
fieldNames = [LOGIN_FIELD, EXPIRE_FIELD, DEPARTMENT_FIELD, GIVENNAME_FIELD, LASTNAME_FIELD, ROLE_FIELD]
fields = map(value_of_field, fieldNames )
return dict(zip(fieldNames, fields))
def clear_expire_date(dic):
if dic[EXPIRE_FIELD] is not None:
expire_datetime = dic[EXPIRE_FIELD].replace(tzinfo=pytz.UTC)
else:
expire_datetime = datetime.datetime(datetime.MAXYEAR, 12, 31, tzinfo=pytz.UTC)
if expire_datetime.year == datetime.MAXYEAR:
expire_datetime = expire_datetime.replace(year=2099, hour=0, minute=0, second=0, microsecond=0)
dic[EXPIRE_FIELD] = expire_datetime
return dic
def clear_department(dic):
dic[DEPARTMENT_FIELD] = string_adjust(dic[DEPARTMENT_FIELD])
return dic
def clear_description(dic):
dic[ROLE_FIELD] = string_adjust(dic[ROLE_FIELD])
return dic
def string_adjust(s):
if s is not None:
return s[:32]
else:
return "N.N."
@@ -0,0 +1,28 @@
# Generated by Django 2.1.4 on 2018-12-10 11:55
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='ActiveDirectoryEntry',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created', models.DateTimeField(editable=False)),
('modified', models.DateTimeField()),
('accountExpires', models.DateTimeField()),
('canonicalName', models.CharField(max_length=32)),
('department', models.CharField(max_length=32)),
('givenName', models.CharField(max_length=32)),
('lastName', models.CharField(max_length=32)),
('role', models.CharField(max_length=32)),
],
),
]
Whitespace-only changes.
+25
View File
@@ -0,0 +1,25 @@
from django.db import models
from django.utils import timezone
class ActiveDirectoryEntry(models.Model):
# id = models.CharField(primary_key=True, max_length=64)
# created = models.DateTimeField(auto_now_add=True)
# modified = models.DateTimeField(auto_now=True)
created = models.DateTimeField(editable=False)
modified = models.DateTimeField()
accountExpires = models.DateTimeField()
canonicalName = models.CharField(max_length=32) #sAMAccountName
department = models.CharField(max_length=32)
givenName = models.CharField(max_length=32)
lastName = models.CharField(max_length=32) #sn
role = models.CharField(max_length=32) #description
def save(self, *args, **kwargs):
''' On save, update timestamps '''
if not self.id:
self.created = timezone.now()
self.modified = timezone.now()
return super(ActiveDirectoryEntry, self).save(*args, **kwargs)
def __str__(self):
return "AD-Entry %s (%s %s)" % (self.canonicalName, self.givenName, self.lastName)
Whitespace-only changes.
@@ -0,0 +1,9 @@
from django import template
from django.contrib.auth.models import Group
register = template.Library()
@register.filter(name='has_group')
def has_group(user, group_name):
group = Group.objects.get(name=group_name)
return True if group in user.groups.all() else False
+17
View File
@@ -0,0 +1,17 @@
from django.test import TestCase
import authstuff.ldap_access
import datetime
import secrets
class ActiveDirTestCase(TestCase):
def setUp(self):
pass
def test_import_ad(self):
delta = datetime.timedelta() # datetime.timedelta(days=2)
last_update = authstuff.ldap_access.last_update()
authstuff.ldap_access.update_entries(secrets.TEST_AD_USER, secrets.TEST_AD_PASSWORD, delta)
self.assertGreater(authstuff.ldap_access.last_update(), last_update)
+20
View File
@@ -0,0 +1,20 @@
import logging
from authstuff.models import ActiveDirectoryEntry
from django.http import JsonResponse
logger = logging.getLogger(__name__)
def detail(request, login):
result = {'canonicalName' : login, 'found' : False}
try:
addata = ActiveDirectoryEntry.objects.get(canonicalName=login)
result['found'] = True
result['role'] = addata.role
result['updated'] = addata.modified
except ActiveDirectoryEntry.DoesNotExist:
pass
response = JsonResponse(result)
return response
+22
View File
@@ -0,0 +1,22 @@
#!/usr/bin/env python
import os
import sys
if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "medinf.settings")
try:
from django.core.management import execute_from_command_line
except ImportError:
# The above import may fail for some other reason. Ensure that the
# issue is really that Django is missing to avoid masking other
# exceptions on Python 2.
try:
import django
except ImportError:
raise ImportError(
"Couldn't import Django. Are you sure it's installed and "
"available on your PYTHONPATH environment variable? Did you "
"forget to activate a virtual environment?"
)
raise
execute_from_command_line(sys.argv)
+36
View File
@@ -0,0 +1,36 @@
import getpass
from ldap3 import Server, Connection, ALL, NTLM, ALL_ATTRIBUTES
print("Authentifizierung gegen ein Active Directory")
# Eingaben
dom = input("Domain [ADS1]:") or "ADS1"
user = input("User [hofmannol]:") or "hofmannol"
print('Password:', end='')
pwd = getpass.getpass()
# Binden an das AD
server = Server('gso1.ads1.fh-nuernberg.de', get_info=ALL)
conn = Connection(
server,
user=dom+"\\"+user,
password=pwd,
authentication=NTLM)
conn.bind()
print(conn)
print(conn.extend.standard.who_am_i())
print(conn.bound)
# Suche nach dem gerade verbundenen User
conn.search(
search_base='DC='+dom+',DC=fh-nuernberg,DC=de',
search_filter='(&(objectclass=user)(CN='+user+'))',
attributes=ALL_ATTRIBUTES)
print(conn.entries[0])
conn.unbind()
View File
Whitespace-only changes.
+4
View File
@@ -0,0 +1,4 @@
from django.conf import settings # import the settings file
def logout_redirect(request):
return {'LOGOUT_REDIRECT_URL': settings.LOGOUT_REDIRECT_URL}
+1
View File
@@ -0,0 +1 @@
loaddata medinf/fixtures/groups.json
+30
View File
@@ -0,0 +1,30 @@
[
{
"model": "auth.group",
"pk": 1,
"fields": {
"name": "PP_ADMIN"
}
},
{
"model": "auth.group",
"pk": 10,
"fields": {
"name": "STUD_VIEW"
}
},
{
"model": "auth.group",
"pk": 11,
"fields": {
"name": "STUD_VIEW_EXTENDED"
}
},
{
"model": "auth.group",
"pk": 12,
"fields": {
"name": "STUD_ADMIN"
}
}
]
+92
View File
@@ -0,0 +1,92 @@
import logging
import traceback
import datetime
from django.contrib.auth.models import User
from ldap3 import Server, Connection, ALL, NTLM, ALL_ATTRIBUTES
from ldap3.core.exceptions import LDAPSocketOpenError
from django.conf import settings
from authstuff.ldap_access import update_entries_with_conn
class LdapBackend(object):
"""
Authenticate against a LDAP directory.
"""
log = logging.getLogger(__name__)
def check_login(self, username, password):
self.log.info("check login {0}".format(username))
server = Server(settings.LDAP_SERVER, connect_timeout=8)
qualified_user = settings.LDAP_DOMAIN + '\\' + username
conn = Connection(server, qualified_user, password=password, authentication=NTLM)
try:
conn.bind()
except LDAPSocketOpenError:
# LDAP Server nicht erreichbar
self.log.warning("LDAP check_login: Server " + settings.LDAP_SERVER + " not reachable.")
return None
except:
var = traceback.format_exc()
self.log.info("LDAP check_login(bind): Unexpected Error %s" % var)
return None
result = None
self.log.info("Bind successful")
try:
if conn.extend.standard.who_am_i() != None:
conn.search(
search_base='DC=' + settings.LDAP_DOMAIN + ',DC=fh-nuernberg,DC=de',
search_filter='(&(objectclass=user)(CN=' + username + '))', attributes=ALL_ATTRIBUTES)
info = conn.entries[0]
result = {'lastname' : str(info.sn),
'givenname' : str(info.givenName),
'login' : str(info.cn),
'department' : str(info.department),
'role' : str(info.description)}
self.log.info("LDAP check_login: %s" % result)
except:
var = traceback.format_exc()
self.log.warning("LDAP check_login: Unexpected Error %s" % var)
try:
delta = datetime.timedelta(days=settings.LDAP_UPDATE_TIMEOUT_DAYS)
update_entries_with_conn(conn, settings.LDAP_DOMAIN, delta)
except:
var = traceback.format_exc()
self.log.warning("LDAP check_login: Update AD Entries failed %s" % var)
return result
def authenticate(self, request, username=None, password=None):
ldap_user = self.check_login(username,password)
if ldap_user:
# {'lastname': 'Hofmann', 'givenname': 'Oliver', 'login': 'hofmannol', 'department': 'EFI', 'role': 'PF'}
# {'lastname': 'Wimmer', 'givenname': 'Martin', 'login': 'wimmerma', 'department': 'EFI', 'role': 'MA'}
# {'lastname': 'Mueller', 'givenname': 'Vincent', 'login': 'muellervi56608', 'department': 'EFI', 'role': 'ST'}
# {'lastname': 'Poehlau', 'givenname': 'Frank', 'login': 'poehlaufr', 'department': 'EFI', 'role': 'PF'}
try:
user = User.objects.get(username=ldap_user['login'])
except User.DoesNotExist:
self.log.info("LDAP authenticate: create new user %s" % ldap_user['login'])
user = User(username=ldap_user['login'])
user.first_name = ldap_user['givenname']
user.last_name = ldap_user['lastname']
user.is_staff = (ldap_user['role'] != 'ST')
user.is_superuser = False
user.save()
return user
return None
def get_user(self, user_id):
try:
return User.objects.get(pk=user_id)
except User.DoesNotExist:
return None
+306
View File
@@ -0,0 +1,306 @@
"""
Django settings for medinf project.
Generated by 'django-admin startproject' using Django 1.11.2.
For more information on this file, see
https://docs.djangoproject.com/en/1.11/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/1.11/ref/settings/
"""
from datetime import timedelta
import os
import re
import socket
# Development or Production
r = re.search(r"^172.17", socket.gethostbyname(socket.gethostname()))
DEVELOPMENT = r == None
DEBUG = True
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = DEVELOPMENT
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# Log Configuration
if DEBUG:
LOGLEVEL = "DEBUG"
else:
LOGLEVEL = "INFO"
LOGGING = {
"version": 1,
"disable_existing_loggers": False,
"formatters": {
"standard": {
"format": "[%(asctime)s] %(levelname)s [%(name)s:%(lineno)s] %(message)s",
"datefmt": "%d/%b/%Y %H:%M:%S",
},
},
"handlers": {
"null": {
"level": "DEBUG",
"class": "logging.NullHandler",
},
"logfile": {
"level": "DEBUG",
"class": "logging.handlers.RotatingFileHandler",
"filename": os.path.join(BASE_DIR, "log/log.txt"),
"maxBytes": 1024 * 1024 * 5,
"backupCount": 5,
"formatter": "standard",
},
"console": {
"level": "DEBUG",
"class": "logging.StreamHandler",
"formatter": "standard",
},
},
"loggers": {
"": {
"level": "WARNING",
"handlers": ["logfile"],
},
"django.db.backends": {
"handlers": ["console"],
"level": "INFO", # set DEBUG if needed
"propagate": False,
},
"medinf": {
"handlers": ["console"],
"level": LOGLEVEL,
"propagate": True,
},
"studis": {
"handlers": ["console"],
"level": LOGLEVEL,
"propagate": True,
},
"authstuff": {
"handlers": ["console"],
"level": "INFO",
"propagate": True,
},
},
}
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = "XXXXXn!i2lx(&)gq7l!art_pr&#9et*$r)r&ogu&j-+wm0^ni5"
USE_X_FORWARDED_HOST = True
ALLOWED_HOSTS = [
"medinf.efi.th-nuernberg.de",
"api.efi.th-nuernberg.de",
"localhost",
"127.0.0.1",
]
# Application definition
INSTALLED_APPS = [
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
# Custom Apps
"authstuff.apps.AuthStuffConfig",
"pruefplan_viewer.apps.PruefplanViewerConfig",
"pruefplan_parser.apps.PruefplanParserConfig",
# Third Party Apps
"rest_framework",
"rest_framework_simplejwt.token_blacklist",
"rest_framework.authtoken",
"corsheaders",
]
MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"corsheaders.middleware.CorsMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
"django.contrib.messages.middleware.MessageMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
]
ROOT_URLCONF = "medinf.urls"
TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [os.path.join(BASE_DIR, "templates")],
"APP_DIRS": True,
"OPTIONS": {
"context_processors": [
"django.template.context_processors.debug",
"django.template.context_processors.request",
"django.contrib.auth.context_processors.auth",
"django.contrib.messages.context_processors.messages",
"medinf.context_processors.logout_redirect",
],
},
},
]
WSGI_APPLICATION = "medinf.wsgi.application"
# Database
# https://docs.djangoproject.com/en/1.11/ref/settings/#databases
if DEVELOPMENT:
DATABASES = {
"default": {
"ENGINE": "django.db.backends.sqlite3",
"NAME": os.path.join(BASE_DIR, "db.sqlite3"),
}
}
else:
DATABASES = {
"default": {
"ENGINE": "django.db.backends.mysql",
"NAME": "django-app",
"USER": "django-app",
"PASSWORD": "8TFXHv9X",
"HOST": "mysql",
"PORT": "3306",
"OPTIONS": {"init_command": "SET sql_mode='STRICT_TRANS_TABLES'"},
}
}
# Password validation
# https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
},
{
"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
},
{
"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
},
{
"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
},
]
# Internationalization
# https://docs.djangoproject.com/en/1.11/topics/i18n/
LANGUAGE_CODE = "de-de"
TIME_ZONE = "Europe/Berlin"
USE_I18N = True
USE_L10N = True
USE_TZ = True
DEFAULT_AUTO_FIELD = "django.db.models.AutoField"
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.11/howto/static-files/
# Nach dem Deployment werden die statischen Inhalte von medinf geholt.
# Sie müssen in das Verzeichnis <HTMLROOT>/static kopiert werden
STATIC_ROOT = os.path.join("/tmp", "static")
STATIC_URL = "/static/"
STATICFILES_DIRS = [
os.path.join(BASE_DIR, "static"),
]
# Konfiguration des Auth-Systems
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.TokenAuthentication',
],
}
LDAP_DOMAIN = "ADS1"
LDAP_SERVER = "gso1.ads1.fh-nuernberg.de"
LDAP_FORCE_UPDATE = False
LDAP_UPDATE_TIMEOUT_DAYS = 2
if DEVELOPMENT:
LOGIN_REDIRECT_URL = "/"
LOGOUT_REDIRECT_URL = "/"
LOGIN_URL = "/accounts/login/"
else:
LOGIN_REDIRECT_URL = "/app/"
LOGOUT_REDIRECT_URL = "/app/"
LOGIN_URL = "/app/accounts/login/"
if DEVELOPMENT:
AUTHENTICATION_BACKENDS = [
"django.contrib.auth.backends.ModelBackend",
]
else:
AUTHENTICATION_BACKENDS = [
"django.contrib.auth.backends.ModelBackend",
"medinf.ldap_backend.LdapBackend",
]
# Config the JWT Token with static settings -> from docs
# https://django-rest-framework-simplejwt.readthedocs.io/en/latest/
SIMPLE_JWT = {
"ACCESS_TOKEN_LIFETIME": timedelta(minutes=15),
"REFRESH_TOKEN_LIFETIME": timedelta(days=50),
"ROTATE_REFRESH_TOKENS": True,
"BLACKLIST_AFTER_ROTATION": True,
"UPDATE_LAST_LOGIN": False,
"ALGORITHM": "HS256",
"VERIFYING_KEY": None,
"AUDIENCE": None,
"ISSUER": None,
"JWK_URL": None,
"LEEWAY": 0,
"AUTH_HEADER_TYPES": ("Bearer",),
"AUTH_HEADER_NAME": "HTTP_AUTHORIZATION",
"USER_ID_FIELD": "id",
"USER_ID_CLAIM": "user_id",
"USER_AUTHENTICATION_RULE": "rest_framework_simplejwt.authentication.default_user_authentication_rule",
"AUTH_TOKEN_CLASSES": ("rest_framework_simplejwt.tokens.AccessToken",),
"TOKEN_TYPE_CLAIM": "token_type",
"TOKEN_USER_CLASS": "rest_framework_simplejwt.models.TokenUser",
"JTI_CLAIM": "jti",
"SLIDING_TOKEN_REFRESH_EXP_CLAIM": "refresh_exp",
"SLIDING_TOKEN_LIFETIME": timedelta(minutes=5),
"SLIDING_TOKEN_REFRESH_LIFETIME": timedelta(days=1),
}
# Set coresheader to allow all origin
CORS_ALLOW_ALL_ORIGINS = True
# Konfiguration Prüfungsplan
PP_UPLOAD_DIR = os.path.join(BASE_DIR, "pruefplan_parser", "data")
PP_TEACHER_FILE = os.path.join(PP_UPLOAD_DIR, "Dozenten.json")
PP_SUBJECT_FILE = os.path.join(PP_UPLOAD_DIR, "Faecher.json")
PP_ATTENDANCE_FILE = os.path.join(PP_UPLOAD_DIR, "Praesenzen.json")
PP_EXAM_FILE = os.path.join(PP_UPLOAD_DIR, "Pruefungen.json")
PP_STUDENT_FILE = os.path.join(PP_UPLOAD_DIR, "Saaleinteilung.json")
+37
View File
@@ -0,0 +1,37 @@
"""medinf URL Configuration
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/1.11/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: url(r'^$', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.conf.urls import url, include
2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls'))
"""
from django.conf.urls import include
from django.contrib import admin
from django.urls import path
from django.views.generic import TemplateView
import medinf.views
urlpatterns = [
path("", TemplateView.as_view(template_name="index.html")),
path("navlogin/", medinf.views.navlogin, name="navlogin"),
path("admin/", admin.site.urls),
path("accounts/", include("django.contrib.auth.urls")),
path("pruefplan_viewer/", include("pruefplan_viewer.urls")),
path("pruefplan_parser/", include("pruefplan_parser.urls")),
path("api/", include("api.urls")), # Link the api urls to the main access point
path(
"authenticate/",
medinf.views.AuthenticateView.as_view(),
name="authenticateView",
), # REST call to authenticate a user in the backend
]
+59
View File
@@ -0,0 +1,59 @@
from django.contrib.auth import authenticate, login, logout
from django.shortcuts import render, redirect
from yaml import serialize
from api.serializer import MyTokenObtainPairSerializer
from api.views import MyTokenObtainPairView
import medinf.settings
import logging
import medinf.ldap_backend
def navlogin(request):
log = logging.getLogger("medinf")
logout(request)
error = ""
if request.POST:
username = request.POST.get("username", "?")
password = request.POST.get("password", "?")
user = authenticate(username=username, password=password)
if user is not None:
if user.is_active:
login(request, user)
return redirect(medinf.settings.LOGIN_REDIRECT_URL)
else:
log.info("Inactive user {} tried to login".format(username))
error = "Ihre Benutzerkennung wurde deaktiviert."
else:
log.info("Login failed for {}".format(username))
error = "Benutzername oder Kennwort falsch."
context = {"error": error}
return render(request, "index.html", context)
################ New REST Token Auth #########################################
from rest_framework_simplejwt.tokens import RefreshToken
from rest_framework.views import APIView
from rest_framework.response import Response
from django.contrib.auth import authenticate
class AuthenticateView(APIView):
def post(self, request):
username = request.data.get("username")
password = request.data.get("password")
user = authenticate(request, username=username, password=password)
if user is not None:
login(request, user) #login the user in the backend
# refresh = RefreshToken.for_user(user)
serializer = MyTokenObtainPairSerializer(data={"username":username, "password":password})
serializer.is_valid(raise_exception=True)
token = serializer.validated_data
return Response(token)
return Response({"error": "Invalid credentials"}, status=400)
+21
View File
@@ -0,0 +1,21 @@
"""
WSGI config for medinf project.
It exposes the WSGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/1.11/howto/deployment/wsgi/
"""
import os
import logging
import medinf.settings
from django.core.wsgi import get_wsgi_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "medinf.settings")
log = logging.getLogger(__name__)
log.info("Starting in %s Environment" % ('DEV' if medinf.settings.DEVELOPMENT else 'PROD'))
application = get_wsgi_application()
Whitespace-only changes.
+3
View File
@@ -0,0 +1,3 @@
from django.contrib import admin
# Register your models here.
+5
View File
@@ -0,0 +1,5 @@
from django.apps import AppConfig
class PruefplanParserConfig(AppConfig):
name = 'pruefplan_parser'
+229
View File
@@ -0,0 +1,229 @@
{
"revision": "2648:2829M",
"array": [
{
"kennung": "259",
"vorname": "Christine",
"nachname": "Rademacher",
"titel": "Prof. Dr.",
"fakultaet": "AMP",
"istLehrbeauftragter": false
},
{
"kennung": "315",
"vorname": "J\u00c3\u00b6rg",
"nachname": "Steinbach",
"titel": "Prof. Dr.",
"fakultaet": "AMP",
"istLehrbeauftragter": false
},
{
"kennung": "385",
"vorname": "Peter",
"nachname": "Jonas",
"titel": "Prof. Dr.",
"fakultaet": "AMP",
"istLehrbeauftragter": false
},
{
"kennung": "71655",
"vorname": "Melanie",
"nachname": "Basting",
"titel": "Prof. Dr.",
"fakultaet": "AMP",
"istLehrbeauftragter": false
},
{
"kennung": "103",
"vorname": "Thomas",
"nachname": "Giesler",
"titel": "Prof. Dr.",
"fakultaet": "EFI",
"istLehrbeauftragter": false
},
{
"kennung": "70901",
"vorname": "Sven",
"nachname": "Loquai",
"titel": "Prof. Dr.-Ing.",
"fakultaet": "EFI",
"istLehrbeauftragter": false
},
{
"kennung": "166",
"vorname": "Bernd",
"nachname": "Klehn",
"titel": "Prof. Dr.",
"fakultaet": "EFI",
"istLehrbeauftragter": false
},
{
"kennung": "382",
"vorname": "Michael",
"nachname": "Zwanger",
"titel": "Prof. Dr.",
"fakultaet": "EFI",
"istLehrbeauftragter": false
},
{
"kennung": "74090",
"vorname": "Olga",
"nachname": "Battermann",
"titel": "Dr.",
"fakultaet": "EFI",
"istLehrbeauftragter": true
},
{
"kennung": "73247",
"vorname": "Michael",
"nachname": "Mayle",
"titel": "Prof. Dr.",
"fakultaet": "AMP",
"istLehrbeauftragter": false
},
{
"kennung": "316",
"vorname": "Florian",
"nachname": "Steinmeyer",
"titel": "Prof. Dr.",
"fakultaet": "AMP",
"istLehrbeauftragter": false
},
{
"kennung": "49",
"vorname": "Bernd",
"nachname": "Braun",
"titel": "Prof. Dr.",
"fakultaet": "AMP",
"istLehrbeauftragter": false
},
{
"kennung": "73630",
"vorname": "Peter",
"nachname": "Eberhardt",
"titel": "Prof. Dr.",
"fakultaet": "EFI",
"istLehrbeauftragter": true
},
{
"kennung": "576",
"vorname": "J\u00c3\u00bcrgen",
"nachname": "Krumm",
"titel": "Prof.",
"fakultaet": "EFI",
"istLehrbeauftragter": false
},
{
"kennung": "219",
"vorname": "Stefan",
"nachname": "May",
"titel": "Prof. Dr.",
"fakultaet": "EFI",
"istLehrbeauftragter": false
},
{
"kennung": "75398",
"vorname": "Christian",
"nachname": "Pfitzner",
"titel": "Prof. Dr.",
"fakultaet": "EFI",
"istLehrbeauftragter": false
},
{
"kennung": "508",
"vorname": "Wolfgang",
"nachname": "M\u00c3\u00b6nch",
"titel": "Prof. Dr.",
"fakultaet": "EFI",
"istLehrbeauftragter": false
},
{
"kennung": "585",
"vorname": "Rainer",
"nachname": "Engelbrecht",
"titel": "Prof. Dr.-Ing.",
"fakultaet": "EFI",
"istLehrbeauftragter": false
},
{
"kennung": "73998",
"vorname": "Stefan",
"nachname": "Wenhardt",
"titel": "",
"fakultaet": "AMP",
"istLehrbeauftragter": true
},
{
"kennung": "74065",
"vorname": "Matthias",
"nachname": "Gleich",
"titel": "",
"fakultaet": "EFI",
"istLehrbeauftragter": true
},
{
"kennung": "376",
"vorname": "Olaf",
"nachname": "Ziemann",
"titel": "Prof. Dr.",
"fakultaet": "EFI",
"istLehrbeauftragter": false
},
{
"kennung": "350",
"vorname": "Sebastian",
"nachname": "Walter",
"titel": "Prof. Dr.",
"fakultaet": "EFI",
"istLehrbeauftragter": false
},
{
"kennung": "75807",
"vorname": "Andreas",
"nachname": "Stute",
"titel": "Prof. Dr.",
"fakultaet": "EFI",
"istLehrbeauftragter": false
},
{
"kennung": "492",
"vorname": "G\u00c3\u00bcnter",
"nachname": "Kie\u00c3\u0178ling",
"titel": "Prof. Dr.",
"fakultaet": "EFI",
"istLehrbeauftragter": false
},
{
"kennung": "84399",
"vorname": "Anja",
"nachname": "Freudenreich",
"titel": "Prof. Dr.",
"fakultaet": "EFI",
"istLehrbeauftragter": false
},
{
"kennung": "38496",
"vorname": "Jan",
"nachname": "Paulus",
"titel": "Prof. Dr.",
"fakultaet": "EFI",
"istLehrbeauftragter": false
},
{
"kennung": "62711",
"vorname": "Hritam",
"nachname": "Dutta",
"titel": "Prof. Dr.",
"fakultaet": "EFI",
"istLehrbeauftragter": false
},
{
"kennung": "73323",
"vorname": "Enrico",
"nachname": "Schr\u00c3\u00b6der;",
"titel": "Prof. Dr.",
"fakultaet": "EFI",
"istLehrbeauftragter": false
}
]
}
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,161 @@
{
"revision": "2648:2829M",
"array": [
{
"dozentenkennung": "103",
"termin": {
"datumText": "22.07.2024 11:00 MESZ",
"jahr": 2024,
"monat": 7,
"tag": 22,
"stunde": 11,
"minute": 0,
"wochentag": "MONTAG",
"pruefungswoche": 2
}
},
{
"dozentenkennung": "70901",
"termin": {
"datumText": "11.07.2024 08:30 MESZ",
"jahr": 2024,
"monat": 7,
"tag": 11,
"stunde": 8,
"minute": 30,
"wochentag": "DONNERSTAG",
"pruefungswoche": 1
}
},
{
"dozentenkennung": "166",
"termin": {
"datumText": "16.07.2024 16:30 MESZ",
"jahr": 2024,
"monat": 7,
"tag": 16,
"stunde": 16,
"minute": 30,
"wochentag": "DIENSTAG",
"pruefungswoche": 1
}
},
{
"dozentenkennung": "382",
"termin": {
"datumText": "16.07.2024 14:00 MESZ",
"jahr": 2024,
"monat": 7,
"tag": 16,
"stunde": 14,
"minute": 0,
"wochentag": "DIENSTAG",
"pruefungswoche": 1
}
},
{
"dozentenkennung": "576",
"termin": {
"datumText": "03.07.2024 11:00 MESZ",
"jahr": 2024,
"monat": 7,
"tag": 3,
"stunde": 11,
"minute": 0,
"wochentag": "MITTWOCH",
"pruefungswoche": 0
}
},
{
"dozentenkennung": "75398",
"termin": {
"datumText": "09.07.2024 11:00 MESZ",
"jahr": 2024,
"monat": 7,
"tag": 9,
"stunde": 11,
"minute": 0,
"wochentag": "DIENSTAG",
"pruefungswoche": 0
}
},
{
"dozentenkennung": "508",
"termin": {
"datumText": "13.07.2024 11:00 MESZ",
"jahr": 2024,
"monat": 7,
"tag": 13,
"stunde": 11,
"minute": 0,
"wochentag": "SAMSTAG",
"pruefungswoche": 1
}
},
{
"dozentenkennung": "585",
"termin": {
"datumText": "13.07.2024 11:00 MESZ",
"jahr": 2024,
"monat": 7,
"tag": 13,
"stunde": 11,
"minute": 0,
"wochentag": "SAMSTAG",
"pruefungswoche": 1
}
},
{
"dozentenkennung": "492",
"termin": {
"datumText": "19.07.2024 11:00 MESZ",
"jahr": 2024,
"monat": 7,
"tag": 19,
"stunde": 11,
"minute": 0,
"wochentag": "FREITAG",
"pruefungswoche": 2
}
},
{
"dozentenkennung": "84399",
"termin": {
"datumText": "26.07.2024 16:30 MESZ",
"jahr": 2024,
"monat": 7,
"tag": 26,
"stunde": 16,
"minute": 30,
"wochentag": "FREITAG",
"pruefungswoche": 3
}
},
{
"dozentenkennung": "38496",
"termin": {
"datumText": "05.07.2024 11:00 MESZ",
"jahr": 2024,
"monat": 7,
"tag": 5,
"stunde": 11,
"minute": 0,
"wochentag": "FREITAG",
"pruefungswoche": 0
}
},
{
"dozentenkennung": "62711",
"termin": {
"datumText": "04.07.2024 14:00 MESZ",
"jahr": 2024,
"monat": 7,
"tag": 4,
"stunde": 14,
"minute": 0,
"wochentag": "DONNERSTAG",
"pruefungswoche": 0
}
}
]
}
@@ -0,0 +1,803 @@
{
"revision": "2648:2829M",
"array": [
{
"kennung": "M1:SU:BEI:1",
"pruefungsart": "LN_STUDIENBEGLEITEND",
"termin": {
"datumText": "10.07.2024 11:00 MESZ",
"jahr": 2024,
"monat": 7,
"tag": 10,
"stunde": 11,
"minute": 0,
"wochentag": "MITTWOCH",
"pruefungswoche": 0
},
"teilpruefungen": [
{
"kennung": "M1:SU:BEI:1",
"anzahlAnmeldungen": 63,
"fachkennungen": [
"BEI:20141:1110"
],
"pruefungsdurchfuehrungen": [
{
"dozentenkennung": "259",
"typ": "PRUEFER",
"raum": "BB.103",
"fachkennungen": [
"BEI:20141:1110"
]
},
{
"dozentenkennung": "315",
"typ": "PRUEFER",
"raum": "KA.450",
"fachkennungen": [
"BEI:20141:1110"
]
},
{
"dozentenkennung": "385",
"typ": "PRUEFER",
"raum": "BB.111",
"fachkennungen": [
"BEI:20141:1110"
]
},
{
"dozentenkennung": "71655",
"typ": "PRUEFER",
"raum": "BB.103",
"fachkennungen": [
"BEI:20141:1110"
]
}
]
}
],
"dozentenKennungPendler": ""
},
{
"kennung": "BMED:20141:5150:\"103,166\"_BMED:20141:5150:\"70901\"_BMED:20201:5150:\"103,166\"",
"pruefungsart": "PRUEFUNG",
"termin": {
"datumText": "11.07.2024 11:00 MESZ",
"jahr": 2024,
"monat": 7,
"tag": 11,
"stunde": 11,
"minute": 0,
"wochentag": "DONNERSTAG",
"pruefungswoche": 1
},
"teilpruefungen": [
{
"kennung": "BMED:20141:5150:\"103,166\"",
"anzahlAnmeldungen": 5,
"fachkennungen": [
"BMED:20141:5150"
],
"pruefungsdurchfuehrungen": [
{
"dozentenkennung": "103",
"typ": "PRUEFER",
"raum": "KA.111",
"fachkennungen": [
"BMED:20141:5150"
]
},
{
"dozentenkennung": "70901",
"typ": "PRUEFER",
"raum": "KA.213",
"fachkennungen": [
"BMED:20141:5150"
]
},
{
"dozentenkennung": "166",
"typ": "PRUEFER",
"raum": "KA.111",
"fachkennungen": [
"BMED:20141:5150"
]
}
]
},
{
"kennung": "BMED:20141:5150:\"70901\"",
"anzahlAnmeldungen": 0,
"fachkennungen": [
"BMED:20141:5150"
],
"pruefungsdurchfuehrungen": [
{
"dozentenkennung": "103",
"typ": "PRUEFER",
"raum": "KA.111",
"fachkennungen": [
"BMED:20141:5150"
]
},
{
"dozentenkennung": "70901",
"typ": "PRUEFER",
"raum": "KA.213",
"fachkennungen": [
"BMED:20141:5150"
]
},
{
"dozentenkennung": "166",
"typ": "PRUEFER",
"raum": "KA.111",
"fachkennungen": [
"BMED:20141:5150"
]
}
]
},
{
"kennung": "BMED:20201:5150:\"103,166\"",
"anzahlAnmeldungen": 41,
"fachkennungen": [
"BMED:20201:5150"
],
"pruefungsdurchfuehrungen": [
{
"dozentenkennung": "103",
"typ": "PRUEFER",
"raum": "KA.111",
"fachkennungen": [
"BMED:20201:5150"
]
},
{
"dozentenkennung": "70901",
"typ": "PRUEFER",
"raum": "KA.213",
"fachkennungen": [
"BMED:20201:5150"
]
},
{
"dozentenkennung": "166",
"typ": "PRUEFER",
"raum": "KA.111",
"fachkennungen": [
"BMED:20201:5150"
]
}
]
}
],
"dozentenKennungPendler": ""
},
{
"kennung": "MZ1PH:SU:BMED:2_PH:SU:BMED:2",
"pruefungsart": "PRUEFUNG",
"termin": {
"datumText": "24.07.2024 14:00 MESZ",
"jahr": 2024,
"monat": 7,
"tag": 24,
"stunde": 14,
"minute": 0,
"wochentag": "MITTWOCH",
"pruefungswoche": 2
},
"teilpruefungen": [
{
"kennung": "MZ1PH:SU:BMED:2",
"anzahlAnmeldungen": 2,
"fachkennungen": [
"BMED:20141:1370"
],
"pruefungsdurchfuehrungen": [
{
"dozentenkennung": "382",
"typ": "PRUEFER",
"raum": "KA.107",
"fachkennungen": [
"BMED:20141:1370"
]
},
{
"dozentenkennung": "74090",
"typ": "PRUEFER",
"raum": "KA.107",
"fachkennungen": [
"BMED:20141:1370"
]
}
]
},
{
"kennung": "PH:SU:BMED:2",
"anzahlAnmeldungen": 101,
"fachkennungen": [
"BMED:20201:1600"
],
"pruefungsdurchfuehrungen": [
{
"dozentenkennung": "73247",
"typ": "PRUEFER",
"raum": "ML.034",
"fachkennungen": [
"BMED:20201:1600"
]
},
{
"dozentenkennung": "316",
"typ": "PRUEFER",
"raum": "KA.140",
"fachkennungen": [
"BMED:20201:1600"
]
},
{
"dozentenkennung": "49",
"typ": "AUFSICHT",
"raum": "ML.034",
"fachkennungen": [
"BMED:20201:1600"
]
}
]
}
],
"dozentenKennungPendler": ""
},
{
"kennung": "126efi:WPF:EFI:0",
"pruefungsart": "LN_VORGEZOGEN",
"teilpruefungen": [],
"dozentenKennungPendler": ""
},
{
"kennung": "MUK:SU:BME:6",
"pruefungsart": "PRUEFUNG",
"teilpruefungen": [
{
"kennung": "MUK:SU:BME:6",
"anzahlAnmeldungen": 0,
"fachkennungen": [
"BME:20131:4520"
],
"pruefungsdurchfuehrungen": []
}
],
"dozentenKennungPendler": ""
},
{
"kennung": "ET1:SU:BMF:1",
"pruefungsart": "LN_STUDIENBEGLEITEND",
"termin": {
"datumText": "03.07.2024 08:30 MESZ",
"jahr": 2024,
"monat": 7,
"tag": 3,
"stunde": 8,
"minute": 30,
"wochentag": "MITTWOCH",
"pruefungswoche": 0
},
"teilpruefungen": [
{
"kennung": "ET1:SU:BMF:1",
"anzahlAnmeldungen": 12,
"fachkennungen": [
"BMF:20171:1180"
],
"pruefungsdurchfuehrungen": [
{
"dozentenkennung": "73630",
"typ": "PRUEFER",
"raum": "KH.108",
"fachkennungen": [
"BMF:20171:1180"
]
},
{
"dozentenkennung": "576",
"typ": "PRUEFER",
"raum": "KH.108",
"fachkennungen": [
"BMF:20171:1180"
]
}
]
}
],
"dozentenKennungPendler": ""
},
{
"kennung": "mAUT4#AB:SU:MSY:1",
"pruefungsart": "PRUEFUNG",
"termin": {
"datumText": "30.07.2024 11:00 MESZ",
"jahr": 2024,
"monat": 7,
"tag": 30,
"stunde": 11,
"minute": 0,
"wochentag": "DIENSTAG",
"pruefungswoche": 3
},
"teilpruefungen": [
{
"kennung": "mAUT4#AB:SU:MSY:1",
"anzahlAnmeldungen": 31,
"fachkennungen": [
"MAPR:20201:8425",
"MSY:20091:8425"
],
"pruefungsdurchfuehrungen": [
{
"dozentenkennung": "219",
"typ": "PRUEFER",
"raum": "KA.213",
"fachkennungen": [
"MAPR:20201:8425",
"MSY:20091:8425"
]
},
{
"dozentenkennung": "75398",
"typ": "PRUEFER",
"raum": "KA.213",
"fachkennungen": [
"MAPR:20201:8425",
"MSY:20091:8425"
]
}
]
}
],
"dozentenKennungPendler": ""
},
{
"kennung": "MAPR:20201:5020:\"393,159,355\"",
"pruefungsart": "LN_VORGEZOGEN",
"teilpruefungen": [],
"dozentenKennungPendler": ""
},
{
"kennung": "TO:SU:BMF:6_TO:SU:BMMF:4",
"pruefungsart": "PRUEFUNG",
"termin": {
"datumText": "13.07.2024 08:30 MESZ",
"jahr": 2024,
"monat": 7,
"tag": 13,
"stunde": 8,
"minute": 30,
"wochentag": "SAMSTAG",
"pruefungswoche": 1
},
"teilpruefungen": [
{
"kennung": "TO:SU:BMMF:4",
"anzahlAnmeldungen": 30,
"fachkennungen": [
"BMED:20141:5350",
"BMED:20201:5350"
],
"pruefungsdurchfuehrungen": [
{
"dozentenkennung": "508",
"typ": "PRUEFER",
"raum": "KA.440",
"fachkennungen": [
"BMED:20141:5350",
"BMED:20201:5350"
]
},
{
"dozentenkennung": "585",
"typ": "PRUEFER",
"raum": "KA.107",
"fachkennungen": [
"BMED:20141:5350",
"BMED:20201:5350"
]
}
]
},
{
"kennung": "TO:SU:BMF:6",
"anzahlAnmeldungen": 29,
"fachkennungen": [
"BMF:20171:4130"
],
"pruefungsdurchfuehrungen": [
{
"dozentenkennung": "508",
"typ": "PRUEFER",
"raum": "KA.440",
"fachkennungen": [
"BMF:20171:4130"
]
},
{
"dozentenkennung": "585",
"typ": "PRUEFER",
"raum": "KA.107",
"fachkennungen": [
"BMF:20171:4130"
]
}
]
}
],
"dozentenKennungPendler": ""
},
{
"kennung": "M1:SU:BMED:1",
"pruefungsart": "LN_STUDIENBEGLEITEND",
"termin": {
"datumText": "10.07.2024 16:30 MESZ",
"jahr": 2024,
"monat": 7,
"tag": 10,
"stunde": 16,
"minute": 30,
"wochentag": "MITTWOCH",
"pruefungswoche": 0
},
"teilpruefungen": [
{
"kennung": "M1:SU:BMED:1",
"anzahlAnmeldungen": 35,
"fachkennungen": [
"BMED:20141:1210",
"BMED:20201:1510"
],
"pruefungsdurchfuehrungen": [
{
"dozentenkennung": "73998",
"typ": "PRUEFER",
"raum": "MC.100",
"fachkennungen": [
"BMED:20141:1210",
"BMED:20201:1510"
]
},
{
"dozentenkennung": "259",
"typ": "PRUEFER",
"raum": "MC.100",
"fachkennungen": [
"BMED:20141:1210",
"BMED:20201:1510"
]
}
]
}
],
"dozentenKennungPendler": ""
},
{
"kennung": "FO:SU:BME:2",
"pruefungsart": "LN_VORGEZOGEN",
"teilpruefungen": [],
"dozentenKennungPendler": ""
},
{
"kennung": "BW:SU:BEI:5",
"pruefungsart": "PRUEFUNG",
"termin": {
"datumText": "11.07.2024 08:30 MESZ",
"jahr": 2024,
"monat": 7,
"tag": 11,
"stunde": 8,
"minute": 30,
"wochentag": "DONNERSTAG",
"pruefungswoche": 1
},
"teilpruefungen": [
{
"kennung": "BW:SU:BEI:5",
"anzahlAnmeldungen": 49,
"fachkennungen": [
"BEI:20141:3800"
],
"pruefungsdurchfuehrungen": [
{
"dozentenkennung": "74065",
"typ": "PRUEFER",
"raum": "MC.100",
"fachkennungen": [
"BEI:20141:3800"
]
},
{
"dozentenkennung": "376",
"typ": "AUFSICHT",
"raum": "KA.111",
"fachkennungen": [
"BEI:20141:3800"
]
}
]
}
],
"dozentenKennungPendler": ""
},
{
"kennung": "MAPR:20201:5810:\"472,60104\"",
"pruefungsart": "LN_VORGEZOGEN",
"teilpruefungen": [],
"dozentenKennungPendler": ""
},
{
"kennung": "MK:SU:BMF:4",
"pruefungsart": "PRUEFUNG",
"termin": {
"datumText": "26.07.2024 08:30 MESZ",
"jahr": 2024,
"monat": 7,
"tag": 26,
"stunde": 8,
"minute": 30,
"wochentag": "FREITAG",
"pruefungswoche": 3
},
"teilpruefungen": [
{
"kennung": "MK:SU:BMF:4",
"anzahlAnmeldungen": 43,
"fachkennungen": [
"BMF:20171:4070"
],
"pruefungsdurchfuehrungen": [
{
"dozentenkennung": "350",
"typ": "PRUEFER",
"raum": "MC.100",
"fachkennungen": [
"BMF:20171:4070"
]
}
]
}
],
"dozentenKennungPendler": ""
},
{
"kennung": "024efi:WPF:EFI:0",
"pruefungsart": "LN_VORGEZOGEN",
"teilpruefungen": [],
"dozentenKennungPendler": ""
},
{
"kennung": "ELK1:SU:BEI:3_IBT:20141:6160:\"166\"",
"pruefungsart": "PRUEFUNG",
"termin": {
"datumText": "27.07.2024 11:00 MESZ",
"jahr": 2024,
"monat": 7,
"tag": 27,
"stunde": 11,
"minute": 0,
"wochentag": "SAMSTAG",
"pruefungswoche": 3
},
"teilpruefungen": [
{
"kennung": "ELK1:SU:BEI:3",
"anzahlAnmeldungen": 36,
"fachkennungen": [
"BEI:20141:5120",
"BMED:20141:5120"
],
"pruefungsdurchfuehrungen": [
{
"dozentenkennung": "166",
"typ": "PRUEFER",
"raum": "MC.100",
"fachkennungen": [
"BEI:20141:5120",
"BMED:20141:5120"
]
}
]
},
{
"kennung": "IBT:20141:6160:\"166\"",
"anzahlAnmeldungen": 6,
"fachkennungen": [
"IBT:20141:6160"
],
"pruefungsdurchfuehrungen": [
{
"dozentenkennung": "166",
"typ": "PRUEFER",
"raum": "MC.100",
"fachkennungen": [
"IBT:20141:6160"
]
}
]
}
],
"dozentenKennungPendler": ""
},
{
"kennung": "mINF6/1:SU:MSY:2",
"pruefungsart": "PRUEFUNG",
"teilpruefungen": [
{
"kennung": "mINF6/1:SU:MSY:2",
"anzahlAnmeldungen": 2,
"fachkennungen": [
"MAPR:20201:8835",
"MSY:20091:8835"
],
"pruefungsdurchfuehrungen": []
}
],
"dozentenKennungPendler": ""
},
{
"kennung": "MSY:20091:8361:\"49,75807\"",
"pruefungsart": "PRUEFUNG",
"termin": {
"datumText": "15.07.2024 08:30 MESZ",
"jahr": 2024,
"monat": 7,
"tag": 15,
"stunde": 8,
"minute": 30,
"wochentag": "MONTAG",
"pruefungswoche": 1
},
"teilpruefungen": [
{
"kennung": "MSY:20091:8361:\"49,75807\"",
"anzahlAnmeldungen": 8,
"fachkennungen": [
"MSY:20091:8361"
],
"pruefungsdurchfuehrungen": [
{
"dozentenkennung": "75807",
"typ": "PRUEFER",
"raum": "KA.217",
"fachkennungen": [
"MSY:20091:8361"
]
},
{
"dozentenkennung": "49",
"typ": "PRUEFER",
"raum": "KA.217",
"fachkennungen": [
"MSY:20091:8361"
]
}
]
}
],
"dozentenKennungPendler": ""
},
{
"kennung": "ET2:SU:BMF:2",
"pruefungsart": "PRUEFUNG",
"termin": {
"datumText": "19.07.2024 08:30 MESZ",
"jahr": 2024,
"monat": 7,
"tag": 19,
"stunde": 8,
"minute": 30,
"wochentag": "FREITAG",
"pruefungswoche": 2
},
"teilpruefungen": [
{
"kennung": "ET2:SU:BMF:2",
"anzahlAnmeldungen": 61,
"fachkennungen": [
"BMF:20171:1190"
],
"pruefungsdurchfuehrungen": [
{
"dozentenkennung": "73630",
"typ": "PRUEFER",
"raum": "BB.103",
"fachkennungen": [
"BMF:20171:1190"
]
},
{
"dozentenkennung": "492",
"typ": "PRUEFER",
"raum": "SP.467",
"fachkennungen": [
"BMF:20171:1190"
]
}
]
}
],
"dozentenKennungPendler": ""
},
{
"kennung": "I2#AB:SU:BEI:3",
"pruefungsart": "LN_STUDIENBEGLEITEND",
"termin": {
"datumText": "04.07.2024 11:00 MESZ",
"jahr": 2024,
"monat": 7,
"tag": 4,
"stunde": 11,
"minute": 0,
"wochentag": "DONNERSTAG",
"pruefungswoche": 0
},
"teilpruefungen": [
{
"kennung": "I2#AB:SU:BEI:3",
"anzahlAnmeldungen": 63,
"fachkennungen": [
"BEI:20141:5160",
"BEI:20141:5160",
"BMED:20141:5160",
"BMED:20141:5160"
],
"pruefungsdurchfuehrungen": [
{
"dozentenkennung": "84399",
"typ": "PRUEFER",
"raum": "BB.103",
"fachkennungen": [
"BEI:20141:5160",
"BEI:20141:5160",
"BMED:20141:5160",
"BMED:20141:5160"
]
},
{
"dozentenkennung": "38496",
"typ": "PRUEFER",
"raum": "KA.450",
"fachkennungen": [
"BEI:20141:5160",
"BEI:20141:5160",
"BMED:20141:5160",
"BMED:20141:5160"
]
},
{
"dozentenkennung": "62711",
"typ": "PRUEFER",
"raum": "BB.210",
"fachkennungen": [
"BEI:20141:5160",
"BEI:20141:5160",
"BMED:20141:5160",
"BMED:20141:5160"
]
},
{
"dozentenkennung": "73323",
"typ": "PRUEFER",
"raum": "BB.103",
"fachkennungen": [
"BEI:20141:5160",
"BEI:20141:5160",
"BMED:20141:5160",
"BMED:20141:5160"
]
}
]
}
],
"dozentenKennungPendler": ""
}
]
}
+1
View File
@@ -0,0 +1 @@
Hier landen die hochgeladenen Dateien
@@ -0,0 +1,577 @@
{
"revision": "2648:2829M",
"array": [
{
"kennungPruefung": "M1:SU:BEI:1",
"termin": {
"datumText": "10.07.2024 11:00 MESZ",
"jahr": 2024,
"monat": 7,
"tag": 10,
"stunde": 11,
"minute": 0,
"wochentag": "MITTWOCH",
"pruefungswoche": 0
},
"raum": "KA.450",
"kennungFaecher": [
"BEI:20141:1110"
],
"matrikel": [
3752511,
3743531,
3726002,
3756960,
3682959,
3747191,
3726312,
3727575,
3677443,
3724433,
3724165,
3748172,
3726338,
3671524,
3684924,
3571059,
3725229,
3678411,
3726268,
3303621,
3732643
]
},
{
"kennungPruefung": "BMED:20141:5150:\"103,166\"_BMED:20141:5150:\"70901\"_BMED:20201:5150:\"103,166\"",
"termin": {
"datumText": "11.07.2024 11:00 MESZ",
"jahr": 2024,
"monat": 7,
"tag": 11,
"stunde": 11,
"minute": 0,
"wochentag": "DONNERSTAG",
"pruefungswoche": 1
},
"raum": "KA.213",
"kennungFaecher": [
"BMED:20141:5150",
"BMED:20141:5150",
"BMED:20201:5150"
],
"matrikel": [
3691111,
3503148,
3680786,
3670499,
3634750,
3706613,
3527650,
3645338,
3706064,
3674877,
3291852,
3676053,
3578540,
3690651,
3621462,
3623453,
3623581,
3673432,
2747059,
3569726,
3673458,
3535000,
3623411
]
},
{
"kennungPruefung": "MZ1PH:SU:BMED:2_PH:SU:BMED:2",
"termin": {
"datumText": "24.07.2024 14:00 MESZ",
"jahr": 2024,
"monat": 7,
"tag": 24,
"stunde": 14,
"minute": 0,
"wochentag": "MITTWOCH",
"pruefungswoche": 2
},
"raum": "KA.107",
"kennungFaecher": [
"BMED:20141:1370"
],
"matrikel": [
3504398,
3516845
]
},
{
"kennungPruefung": "ET1:SU:BMF:1",
"termin": {
"datumText": "03.07.2024 08:30 MESZ",
"jahr": 2024,
"monat": 7,
"tag": 3,
"stunde": 8,
"minute": 30,
"wochentag": "MITTWOCH",
"pruefungswoche": 0
},
"raum": "KH.108",
"kennungFaecher": [
"BMF:20171:1180"
],
"matrikel": [
3584222,
3569599,
3565942,
3749645,
3756449,
3698347,
3628502,
3182142,
3673742,
3719352,
3693298,
3756564
]
},
{
"kennungPruefung": "mAUT4#AB:SU:MSY:1",
"termin": {
"datumText": "30.07.2024 11:00 MESZ",
"jahr": 2024,
"monat": 7,
"tag": 30,
"stunde": 11,
"minute": 0,
"wochentag": "DIENSTAG",
"pruefungswoche": 3
},
"raum": "KA.213",
"kennungFaecher": [
"MAPR:20201:8425",
"MSY:20091:8425"
],
"matrikel": [
3716009,
3518430,
3506909,
3513240,
3503119,
3724136,
3767142,
3767155,
3707610,
3508565,
3503429,
3581599,
3754052,
3516832,
3772463,
3508680,
3505960,
3569630,
3577853,
3244724,
3502563,
3503094,
3580352,
3164060,
3502873,
3559848,
3723960,
3758612,
3513224,
3289528,
3768800
]
},
{
"kennungPruefung": "TO:SU:BMF:6_TO:SU:BMMF:4",
"termin": {
"datumText": "13.07.2024 08:30 MESZ",
"jahr": 2024,
"monat": 7,
"tag": 13,
"stunde": 8,
"minute": 30,
"wochentag": "SAMSTAG",
"pruefungswoche": 1
},
"raum": "KA.107",
"kennungFaecher": [
"BMED:20141:5350",
"BMED:20201:5350",
"BMF:20171:4130"
],
"matrikel": [
3622836,
3574261,
3529162,
3617023,
3616170,
3615636,
3629947,
3584699,
3624405,
3556537,
3616138,
3513422,
3619874,
3621178,
3623929,
2984098,
2931071,
3513266,
2267607
]
},
{
"kennungPruefung": "M1:SU:BMED:1",
"termin": {
"datumText": "10.07.2024 16:30 MESZ",
"jahr": 2024,
"monat": 7,
"tag": 10,
"stunde": 16,
"minute": 30,
"wochentag": "MITTWOCH",
"pruefungswoche": 0
},
"raum": "MC.100",
"kennungFaecher": [
"BMED:20141:1210",
"BMED:20201:1510"
],
"matrikel": [
3733583,
3746008,
3751361,
3673445,
3739767,
3749629,
3719307,
3742617,
3740220,
3720860,
3721838,
3504653,
3754586,
3726479,
3561069,
3727869,
3740275,
3728051,
3724967,
3512920,
3581490,
3711062,
3759862,
3649154,
3756551,
3636093,
3719266,
3635348,
3719563,
3727393,
3761041,
3691393,
3638266,
3633414,
3622852
]
},
{
"kennungPruefung": "BW:SU:BEI:5",
"termin": {
"datumText": "11.07.2024 08:30 MESZ",
"jahr": 2024,
"monat": 7,
"tag": 11,
"stunde": 8,
"minute": 30,
"wochentag": "DONNERSTAG",
"pruefungswoche": 1
},
"raum": "MC.100",
"kennungFaecher": [
"BEI:20141:3800"
],
"matrikel": [
3616675,
3647725,
3627406,
3572030,
3235621,
3161199,
3512045,
3628672,
3308517,
3235250,
3634396,
3616703,
3627381,
3085850,
3620436,
3622159,
3569205,
3628205,
3263104,
3516957,
3628630,
3615850,
3647866,
3627419,
3641161,
3627831,
3622191,
3017956
]
},
{
"kennungPruefung": "MK:SU:BMF:4",
"termin": {
"datumText": "26.07.2024 08:30 MESZ",
"jahr": 2024,
"monat": 7,
"tag": 26,
"stunde": 8,
"minute": 30,
"wochentag": "FREITAG",
"pruefungswoche": 3
},
"raum": "MC.100",
"kennungFaecher": [
"BMF:20171:4070"
],
"matrikel": [
3544163,
3643800,
3621545,
3668827,
3569599,
3678479,
3246109,
3698350,
3583791,
3678437,
3693511,
3619902,
3699683,
3733244,
3627394,
3667523,
3700385,
3678226,
3698839,
3678495,
3036482,
3678440,
3684474,
3664621,
3698347,
3693243,
3564309,
3629947,
3584699,
3645721,
3687433,
3693269,
3678242,
3638914,
3619874,
3678424,
3234192,
3682438,
3669428,
3665967,
3693272,
3706626,
3665222
]
},
{
"kennungPruefung": "ELK1:SU:BEI:3_IBT:20141:6160:\"166\"",
"termin": {
"datumText": "27.07.2024 11:00 MESZ",
"jahr": 2024,
"monat": 7,
"tag": 27,
"stunde": 11,
"minute": 0,
"wochentag": "SAMSTAG",
"pruefungswoche": 3
},
"raum": "MC.100",
"kennungFaecher": [
"BEI:20141:5120",
"BMED:20141:5120",
"IBT:20141:6160"
],
"matrikel": [
3569979,
3647684,
3572030,
3633737,
3530133,
3509559,
3627381,
3085850,
3706121,
3670064,
3513381,
3263104,
3670402,
3670936,
3536119,
3692598,
3615272,
3692639,
3692668,
3671962,
3667932,
3672617,
3692837,
3674822,
3671805,
3513026,
3670051,
3693214,
3577712,
3668517,
3673586,
3672068,
3702392,
3722314,
3645792,
3534748,
3638394,
3305701,
3291335,
3637256,
3589933,
3589988
]
},
{
"kennungPruefung": "MSY:20091:8361:\"49,75807\"",
"termin": {
"datumText": "15.07.2024 08:30 MESZ",
"jahr": 2024,
"monat": 7,
"tag": 15,
"stunde": 8,
"minute": 30,
"wochentag": "MONTAG",
"pruefungswoche": 1
},
"raum": "KA.217",
"kennungFaecher": [
"MSY:20091:8361"
],
"matrikel": [
3581599,
2761145,
3132088,
3757011,
2694152,
3768798,
3713545,
3506826
]
},
{
"kennungPruefung": "ET2:SU:BMF:2",
"termin": {
"datumText": "19.07.2024 08:30 MESZ",
"jahr": 2024,
"monat": 7,
"tag": 19,
"stunde": 8,
"minute": 30,
"wochentag": "FREITAG",
"pruefungswoche": 2
},
"raum": "SP.467",
"kennungFaecher": [
"BMF:20171:1190"
],
"matrikel": [
3726495,
3756449,
3721148,
3664621,
3721825,
3698347,
3628502,
3720831,
3182142,
3742505,
3250956,
3720901,
3688315,
3719253,
3720844,
3673742,
3513422,
3726239,
3719237,
3753899,
2984098,
3234192,
3719352,
3257531,
3693298,
3198761,
3756564,
3726099,
3719914
]
},
{
"kennungPruefung": "I2#AB:SU:BEI:3",
"termin": {
"datumText": "04.07.2024 11:00 MESZ",
"jahr": 2024,
"monat": 7,
"tag": 4,
"stunde": 11,
"minute": 0,
"wochentag": "DONNERSTAG",
"pruefungswoche": 0
},
"raum": "KA.450",
"kennungFaecher": [
"BEI:20141:5160",
"BEI:20141:5160",
"BMED:20141:5160",
"BMED:20141:5160"
],
"matrikel": [
3641161,
3670936,
3565575,
3536119,
3570982,
3615272,
3692613,
3570627,
3629017,
3590623,
3629033,
3667932,
3706118,
3702389,
3630286,
3283310,
3715284,
3671087,
3271030,
3674822,
3665277
]
}
]
}
+9
View File
@@ -0,0 +1,9 @@
from django import forms
class UploadFileForm(forms.Form):
student_file = forms.FileField(required=False)
exams_file = forms.FileField(required=False)
lecturers_file = forms.FileField(required=False)
subjects_file = forms.FileField(required=False)
attendance_file = forms.FileField(required=False)
@@ -0,0 +1,20 @@
# Generated by Django 3.2 on 2021-04-30 12:03
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='JsonParser',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
],
),
]
Whitespace-only changes.
+454
View File
@@ -0,0 +1,454 @@
import inspect
from django.db import models
from medinf.settings import (
PP_EXAM_FILE,
PP_ATTENDANCE_FILE,
PP_STUDENT_FILE,
PP_SUBJECT_FILE,
PP_TEACHER_FILE,
)
from pruefplan_viewer.models import (
API_ExamDataSet_ForStudent,
Attendance,
Subject,
Exam,
Lecturer,
PartialExam,
ExamExecution,
Student,
StudentExam,
)
import json
import datetime
class JsonParser(models.Model):
exceptionMessages = []
warningMessages = []
def clearTable(self):
JsonParser.exceptionMessages.clear()
JsonParser.warningMessages.clear()
Subject.objects.all().delete()
Exam.objects.all().delete()
Attendance.objects.all().delete()
Lecturer.objects.all().delete()
Student.objects.all().delete()
PartialExam.objects.all().delete()
ExamExecution.objects.all().delete()
StudentExam.objects.all().delete()
API_ExamDataSet_ForStudent.objects.all().delete()
def fillLecturerTable(self):
idKey = "kennung"
firstNameKey = "vorname"
lastNameKey = "nachname"
titleKey = "titel"
try:
with open(PP_TEACHER_FILE, encoding="utf-8") as json_file:
data = json.load(json_file)
revision = data["revision"] # TODO -> Do Something with Revision
for d in data["array"]:
entry = Lecturer(
identification=d[idKey],
firstName=d[firstNameKey],
lastName=d[lastNameKey],
title=d[titleKey],
) # Create new Lecturer entry
entry.save()
except FileNotFoundError as e:
JsonParser.exceptionMessages.append(
"Exception of type [FileNotFound]. Message: " + str(e)
)
except KeyError as e:
calling_function = inspect.stack()[0][3]
iteration_number = data["array"].index(d)
template = "Exception of type [{0}] occurred in function {1} in iteration {2} of the loop.. Arguments: {3!r}. Message: [{4}] entry might be missing in {5!r}"
message = template.format(
type(e).__name__,
calling_function,
iteration_number,
e.args,
e,
PP_TEACHER_FILE,
)
JsonParser.exceptionMessages.append(message)
except Exception as e:
calling_function = inspect.stack()[0][3]
template = "Exception of type [{0}] occurred in function {1} in iteration {2} of the loop. Arguments: {3!r}. Message: {4}."
message = template.format(
type(e).__name__,
calling_function,
iteration_number,
e.args,
e.__str__(),
)
JsonParser.exceptionMessages.append(message)
def fillAttendanceTable(self):
idKey = "dozentenkennung"
yearKey = "jahr"
monthKey = "monat"
dayKey = "tag"
hourKey = "stunde"
minuteKey = "minute"
weekdayKey = "wochentag"
dateKey = "termin"
try:
with open(PP_ATTENDANCE_FILE, encoding="utf-8") as json_file:
data = json.load(json_file)
revision = data["revision"] # TODO -> Do Something with Revision
for d in data["array"]:
keyAvailable = "termin" in d
if (
not keyAvailable
): # These attendance entries were not assigned any examination date
template = "Warning. Location: {0!r}. Following Exam was not assigned any examination date ['termin']: [{1}]"
message = template.format(PP_EXAM_FILE, d[idKey])
JsonParser.warningMessages.append(message)
continue
date = datetime.date(
d[dateKey][yearKey], d[dateKey][monthKey], d[dateKey][dayKey]
)
time = datetime.time(d[dateKey][hourKey], d[dateKey][minuteKey])
entry = Attendance(
identification=d[idKey],
time=time,
date=date,
dateTimeText=d[dateKey]["datumText"],
weekday=d[dateKey]["wochentag"],
) # Create new Lecturer entry
entry.save()
try:
# Get the Lecturer with the "Dozentenkennung" of this attendance entry
lecturer = Lecturer.objects.get(identification=d[idKey])
# Link this attendance entry to the lecturer
lecturer.attendance_set.add(entry)
except Exception as e:
template = "Exception of type [{0}]. Arguments: {1!r}. Message: [{2}] entry might be missing in {3!r}"
message = template.format(
type(e).__name__, e.args, idKey, PP_TEACHER_FILE
)
JsonParser.exceptionMessages.append(message)
except FileNotFoundError as e:
JsonParser.exceptionMessages.append(
"Exception of type [FileNotFound]. Message: " + str(e)
)
except KeyError as e:
calling_function = inspect.stack()[0][3]
iteration_number = data["array"].index(d)
template = "Exception of type [{0}] occurred in function {1} in iteration {2} of the loop.. Arguments: {3!r}. Message: [{4}] entry might be missing in {5!r}"
message = template.format(
type(e).__name__,
calling_function,
iteration_number,
e.args,
e,
PP_ATTENDANCE_FILE,
)
JsonParser.exceptionMessages.append(message)
except Exception as e:
calling_function = inspect.stack()[0][3]
iteration_number = data["array"].index(d)
template = "Exception of type [{0}] occurred in function {1} in iteration {2} of the loop. Arguments: {3!r}. Message: {4}."
message = template.format(
type(e).__name__,
calling_function,
iteration_number,
e.args,
e.__str__(),
)
JsonParser.exceptionMessages.append(message)
def fillSubjectTable(self):
idKey = "kennung"
initialsKey = "kurztext"
nameKey = "langtext"
ohmIdKey = "fachkennungOhm"
try:
with open(PP_SUBJECT_FILE, encoding="utf-8") as json_file:
data = json.load(json_file)
revision = data["revision"] # TODO -> Do Something with Revision
for d in data["array"]:
entry = Subject(
identification=d[idKey],
initials=d[ohmIdKey][initialsKey],
name=d[ohmIdKey][nameKey],
) # Create new Subject entry
entry.save()
except FileNotFoundError as e:
JsonParser.exceptionMessages.append(
"Exception of type [FileNotFound]. Message:" + str(e)
)
except KeyError as e:
calling_function = inspect.stack()[0][3]
iteration_number = data["array"].index(d)
template = "Exception of type [{0}] occurred in function {1} in iteration {2} of the loop.. Arguments: {3!r}. Message: [{4}] entry might be missing in {5!r}"
message = template.format(
type(e).__name__,
calling_function,
iteration_number,
e.args,
e,
PP_SUBJECT_FILE,
)
JsonParser.exceptionMessages.append(message)
except Exception as e:
calling_function = inspect.stack()[0][3]
iteration_number = data["array"].index(d)
template = "Exception of type [{0}] occurred in function {1} in iteration {2} of the loop. Arguments: {3!r}. Message: {4}."
message = template.format(
type(e).__name__,
calling_function,
iteration_number,
e.args,
e.__str__(),
)
JsonParser.exceptionMessages.append(message)
def fillExamTable(self):
idKey = "kennung"
yearKey = "jahr"
monthKey = "monat"
dayKey = "tag"
hourKey = "stunde"
minuteKey = "minute"
weekdayKey = "wochentag"
dateKey = "termin"
partialExamsKey = "teilpruefungen"
partialExamIdKey = "kennung"
numRegStudKey = "anzahlAnmeldungen"
subjectIdsKey = "fachkennungen"
examExecutionsKey = "pruefungsdurchfuehrungen"
lecturerIdKey = "dozentenkennung"
supervisorTypeKey = "typ"
locationKey = "raum"
try:
with open(PP_EXAM_FILE, encoding="utf-8") as json_file:
data = json.load(json_file)
revision = data["revision"] # TODO -> Do Something with Revision
for d in data["array"]:
if (
d["pruefungsart"] == "LN_VORGEZOGEN"
): # These entries can be ignored
continue
keyAvailable = "termin" in d
if (
not keyAvailable
): # These exam entries were not assigned any examination date
template = "Warning. Location: {0!r}. Following Exam was not assigned any examination date ['termin']: [{1}]"
message = template.format(PP_EXAM_FILE, d[idKey])
JsonParser.warningMessages.append(message)
continue
date = datetime.date(
d[dateKey][yearKey], d[dateKey][monthKey], d[dateKey][dayKey]
)
time = datetime.time(d[dateKey][hourKey], d[dateKey][minuteKey])
examEntry = Exam(
identification=d[idKey],
date=date,
time=time,
weekday=d[dateKey][weekdayKey],
) # Create new Exam entry
examEntry.save()
for teilpruef in d[partialExamsKey]:
partialExamId = teilpruef[partialExamIdKey]
regStudCount = teilpruef[numRegStudKey]
partialExam = PartialExam(
identification=partialExamId, regStudCount=regStudCount
) # Create new Partialexam entry
partialExam.save()
examEntry.partialexam_set.add(
partialExam
) # Add connection Exam(One) to PartialExam(Many)
for subId in teilpruef[subjectIdsKey]:
# check if subject exists
try:
subject = Subject.objects.get(identification=subId)
partialExam.subjectIds.add(
subject
) # Add connection PartialExam(Many) to Subject(Many)
except Exception as e:
template = "Exception of type [{0}]. Arguments: {1!r}. Message: [{2}] entry might be missing in {3!r}"
message = template.format(
type(e).__name__, e.args, subId, PP_SUBJECT_FILE
)
JsonParser.exceptionMessages.append(message)
for pruefdurch in teilpruef[examExecutionsKey]:
lecId = pruefdurch[lecturerIdKey]
supervisorType = pruefdurch[supervisorTypeKey]
location = pruefdurch[locationKey]
examExecution = ExamExecution(
supervisorType=supervisorType, location=location
) # Create new ExamExecution entry
examExecution.save()
# check if lecturer exists
try:
lecturer = Lecturer.objects.get(pk=lecId)
lecturer.examexecution_set.add(
examExecution
) # Add connection Lecturer (One) to ExamExecution (Many)
except Exception as e:
template = "Exception of type [{0}]. Arguments: {1!r}. Message: [{2}] entry might be missing in {3!r}"
message = template.format(
type(e).__name__, e.args, lecId, PP_TEACHER_FILE
)
JsonParser.exceptionMessages.append(message)
for subId in pruefdurch[subjectIdsKey]:
# check if subject exists
try:
subject = Subject.objects.get(identification=subId)
examExecution.subjectIds.add(
subject
) # Add connection ExamExecution(Many) to Subject(Many)
except Exception as e:
template = "Exception of type [{0}]. Arguments: {1!r}. Message: [{2}] entry might be missing in {3!r}"
message = template.format(
type(e).__name__, e.args, subId, PP_SUBJECT_FILE
)
JsonParser.exceptionMessages.append(message)
partialExam.examexecution_set.add(
examExecution
) # Add connection PartialExam(One) to ExamExecution(Many)
except FileNotFoundError as e:
JsonParser.exceptionMessages.append(
"Exception of type [FileNotFound]. Message" + str(e)
)
except KeyError as e:
calling_function = inspect.stack()[0][3]
iteration_number = data["array"].index(d)
template = "Exception of type [{0}] occurred in function {1} in iteration {2} of the loop.. Arguments: {3!r}. Message: [{4}] entry might be missing in {5!r}"
message = template.format(
type(e).__name__,
calling_function,
iteration_number,
e.args,
e,
PP_EXAM_FILE,
)
JsonParser.exceptionMessages.append(message)
except Exception as e:
calling_function = inspect.stack()[0][3]
iteration_number = data["array"].index(d)
template = "Exception of type [{0}] occurred in function {1} in iteration {2} of the loop. Arguments: {3!r}. Message: {4}."
message = template.format(
type(e).__name__,
calling_function,
iteration_number,
e.args,
e.__str__(),
)
JsonParser.exceptionMessages.append(message)
def fillStudentExamTable(self):
idKey = "kennungPruefung"
yearKey = "jahr"
monthKey = "monat"
dayKey = "tag"
hourKey = "stunde"
minuteKey = "minute"
weekdayKey = "wochentag"
locationKey = "raum"
dateKey = "termin"
matrikelKey = "matrikel"
try:
with open(PP_STUDENT_FILE, encoding="utf-8") as json_file:
data = json.load(json_file)
revision = data["revision"] # TODO -> Do Something with Revision
for d in data["array"]:
date = datetime.date(
d[dateKey][yearKey], d[dateKey][monthKey], d[dateKey][dayKey]
)
time = datetime.time(d[dateKey][hourKey], d[dateKey][minuteKey])
exam = Exam.objects.filter(
identification=d[idKey], date=date, time=time
).first()
partialExams = exam.partialexam_set.all()
for partialExam in partialExams:
examExecutions = partialExam.examexecution_set.all()
for examExecution in examExecutions:
if examExecution.location == d[locationKey]:
studentExamEntry = StudentExam(
examIdentification=d[idKey],
date=date,
time=time,
weekday=d[dateKey][weekdayKey],
location=d[locationKey],
examExecution=examExecution,
) # Create new StudentExam entry
studentExamEntry.save()
for matrikel in d[matrikelKey]:
studentEntry = Student.objects.filter(
matrikel=matrikel
).exists()
if (
studentEntry is False
): # Create new Student entry if does not already exists
entry = Student(matrikel=matrikel)
entry.save()
else:
entry = (
Student.objects.all().filter(matrikel=matrikel).first()
)
entry.exams.add(studentExamEntry)
except FileNotFoundError as e:
JsonParser.exceptionMessages.append(
"Exception of type [FileNotFound]. Message:" + str(e)
)
except KeyError as e:
calling_function = inspect.stack()[0][3]
iteration_number = data["array"].index(d)
template = "Exception of type [{0}] occurred in function {1} in iteration {2} of the loop.. Arguments: {3!r}. Message: [{4}] entry might be missing in {5!r}"
message = template.format(
type(e).__name__,
calling_function,
iteration_number,
e.args,
e,
PP_STUDENT_FILE,
)
JsonParser.exceptionMessages.append(message)
except Exception as e:
calling_function = inspect.stack()[0][3]
iteration_number = data["array"].index(d)
template = "Exception of type [{0}] occurred in function {1} in iteration {2} of the loop. Arguments: {3!r}. Message: {4}."
message = template.format(
type(e).__name__,
calling_function,
iteration_number,
e.args,
e.__str__(),
)
JsonParser.exceptionMessages.append(message)
+10
View File
@@ -0,0 +1,10 @@
from django.urls import path
from . import views
app_name = 'pp_parser'
urlpatterns = [
path('parse', views.parse, name='parse'),
path('clearTable', views.clearTable, name='clearTable'),
path('upload_file', views.upload_file, name='upload_file'),
]
+7
View File
@@ -0,0 +1,7 @@
def handle_uploaded_file(f, location):
if f is not None:
with open(location, 'wb+') as destination:
for chunk in f.chunks():
destination.write(chunk)
+65
View File
@@ -0,0 +1,65 @@
from django.shortcuts import render
from .models import JsonParser
from pruefplan_parser.models import JsonParser
from django.shortcuts import render
from django.contrib.auth.decorators import user_passes_test
from .forms import UploadFileForm
from pruefplan_parser.utils import handle_uploaded_file
from medinf.settings import (
PP_EXAM_FILE,
PP_ATTENDANCE_FILE,
PP_STUDENT_FILE,
PP_SUBJECT_FILE,
PP_TEACHER_FILE,
)
def is_pp_admin(user):
return user.groups.filter(name="PP_ADMIN").exists()
def parse():
parser = JsonParser()
parser.clearTable()
parser.fillLecturerTable()
parser.fillAttendanceTable()
parser.fillSubjectTable()
parser.fillExamTable()
parser.fillStudentExamTable()
@user_passes_test(is_pp_admin)
def clearTable(request):
parser = JsonParser()
parser.clearTable()
return render(request, "pruefplan/clearTable.html")
@user_passes_test(is_pp_admin)
def upload_file(request):
if request.method == "POST":
form = UploadFileForm(request.POST, request.FILES)
if form.is_valid():
print(request.FILES)
handle_uploaded_file(
request.FILES.get("attendance_file"), PP_ATTENDANCE_FILE
)
handle_uploaded_file(request.FILES.get("student_file"), PP_STUDENT_FILE)
handle_uploaded_file(request.FILES.get("exams_file"), PP_EXAM_FILE)
handle_uploaded_file(request.FILES.get("lecturers_file"), PP_TEACHER_FILE)
handle_uploaded_file(request.FILES.get("subjects_file"), PP_SUBJECT_FILE)
parse()
if (
len(JsonParser.exceptionMessages) != 0
or len(JsonParser.warningMessages) != 0
):
context = {
"exceptions": JsonParser.exceptionMessages,
"warnings": JsonParser.warningMessages,
}
return render(request, "pruefplan/exceptionHandling.html", context)
else:
return render(request, "pruefplan/parse.html")
else:
form = UploadFileForm()
return render(request, "pruefplan/upload.html", {"form": form})
Whitespace-only changes.
+4
View File
@@ -0,0 +1,4 @@
#from django.contrib import admin
#from .models import Lecturer
#admin.site.register(Lecturer)
+5
View File
@@ -0,0 +1,5 @@
from django.apps import AppConfig
class PruefplanViewerConfig(AppConfig):
name = 'pruefplan_viewer'
@@ -0,0 +1,94 @@
# Generated by Django 3.2 on 2021-04-30 12:03
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='Exam',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('identification', models.CharField(max_length=200, null=True)),
('date', models.DateField(blank=True, null=True)),
('time', models.TimeField(blank=True, null=True)),
('weekday', models.CharField(max_length=200, null=True)),
],
),
migrations.CreateModel(
name='ExamExecution',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('supervisorType', models.CharField(max_length=200, null=True)),
('location', models.CharField(max_length=200, null=True)),
],
),
migrations.CreateModel(
name='Lecturer',
fields=[
('identification', models.CharField(max_length=200, primary_key=True, serialize=False)),
('firstName', models.CharField(max_length=200, null=True)),
('lastName', models.CharField(max_length=200, null=True)),
('title', models.CharField(max_length=200, null=True)),
],
),
migrations.CreateModel(
name='Subject',
fields=[
('identification', models.CharField(max_length=200, primary_key=True, serialize=False)),
('initials', models.CharField(max_length=200, null=True)),
('name', models.CharField(max_length=200, null=True)),
],
),
migrations.CreateModel(
name='StudentExam',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('examIdentification', models.CharField(max_length=200, null=True)),
('date', models.DateField(blank=True, null=True)),
('time', models.TimeField(blank=True, null=True)),
('weekday', models.CharField(max_length=200, null=True)),
('location', models.CharField(max_length=200, null=True)),
('examExecution', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='pruefplan_viewer.examexecution')),
],
),
migrations.CreateModel(
name='Student',
fields=[
('matrikel', models.CharField(max_length=200, primary_key=True, serialize=False)),
('exams', models.ManyToManyField(to='pruefplan_viewer.StudentExam')),
],
),
migrations.CreateModel(
name='PartialExam',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('identification', models.CharField(max_length=200, null=True)),
('regStudCount', models.CharField(max_length=200, null=True)),
('exam', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='pruefplan_viewer.exam')),
('subjectIds', models.ManyToManyField(to='pruefplan_viewer.Subject')),
],
),
migrations.AddField(
model_name='examexecution',
name='lecturer',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='pruefplan_viewer.lecturer'),
),
migrations.AddField(
model_name='examexecution',
name='partialExam',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='pruefplan_viewer.partialexam'),
),
migrations.AddField(
model_name='examexecution',
name='subjectIds',
field=models.ManyToManyField(to='pruefplan_viewer.Subject'),
),
]
@@ -0,0 +1,18 @@
# Generated by Django 5.0.2 on 2024-02-26 17:04
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
("pruefplan_viewer", "0001_initial"),
]
operations = [
migrations.AlterModelOptions(
name="examexecution",
options={
"ordering": ("partialExam__exam__date", "partialExam__exam__time")
},
),
]
@@ -0,0 +1,19 @@
# Generated by Django 5.0.2 on 2024-04-11 13:46
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('pruefplan_viewer', '0002_alter_examexecution_options'),
]
operations = [
migrations.CreateModel(
name='Presences',
fields=[
('identification', models.CharField(max_length=200, primary_key=True, serialize=False)),
],
),
]
@@ -0,0 +1,33 @@
# Generated by Django 5.0.2 on 2024-04-11 16:30
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('pruefplan_viewer', '0003_presences'),
]
operations = [
migrations.AddField(
model_name='presences',
name='date',
field=models.DateField(blank=True, null=True),
),
migrations.AddField(
model_name='presences',
name='dateTimeText',
field=models.CharField(max_length=200, null=True),
),
migrations.AddField(
model_name='presences',
name='time',
field=models.TimeField(blank=True, null=True),
),
migrations.AddField(
model_name='presences',
name='weekday',
field=models.CharField(max_length=200, null=True),
),
]
@@ -0,0 +1,19 @@
# Generated by Django 5.0.3 on 2024-04-24 09:13
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('pruefplan_viewer', '0004_presences_date_presences_datetimetext_presences_time_and_more'),
]
operations = [
migrations.AddField(
model_name='presences',
name='lecturer',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='pruefplan_viewer.lecturer'),
),
]
@@ -0,0 +1,17 @@
# Generated by Django 5.0.3 on 2024-05-17 10:43
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('pruefplan_viewer', '0005_presences_lecturer'),
]
operations = [
migrations.RenameModel(
old_name='Presences',
new_name='Attendance',
),
]
@@ -0,0 +1,19 @@
# Generated by Django 5.1.4 on 2025-01-30 14:14
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('pruefplan_viewer', '0006_rename_presences_attendance'),
]
operations = [
migrations.CreateModel(
name='API_ExamDataSet_ForStudent',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
],
),
]
@@ -0,0 +1,63 @@
# Generated by Django 5.1.4 on 2025-01-30 14:19
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('pruefplan_viewer', '0007_api_examdataset_forstudent'),
]
operations = [
migrations.AddField(
model_name='api_examdataset_forstudent',
name='date',
field=models.DateField(blank=True, null=True),
),
migrations.AddField(
model_name='api_examdataset_forstudent',
name='examIdent',
field=models.CharField(max_length=200, null=True),
),
migrations.AddField(
model_name='api_examdataset_forstudent',
name='examStudCount',
field=models.CharField(max_length=200, null=True),
),
migrations.AddField(
model_name='api_examdataset_forstudent',
name='location',
field=models.CharField(max_length=200, null=True),
),
migrations.AddField(
model_name='api_examdataset_forstudent',
name='room',
field=models.CharField(max_length=200, null=True),
),
migrations.AddField(
model_name='api_examdataset_forstudent',
name='studMartNr',
field=models.CharField(max_length=200, null=True),
),
migrations.AddField(
model_name='api_examdataset_forstudent',
name='subjectIdent',
field=models.CharField(max_length=200, null=True),
),
migrations.AddField(
model_name='api_examdataset_forstudent',
name='supervisor',
field=models.CharField(max_length=200, null=True),
),
migrations.AddField(
model_name='api_examdataset_forstudent',
name='time',
field=models.TimeField(blank=True, null=True),
),
migrations.AddField(
model_name='api_examdataset_forstudent',
name='weekday',
field=models.CharField(max_length=200, null=True),
),
]
Whitespace-only changes.
+148
View File
@@ -0,0 +1,148 @@
from __future__ import annotations # Python 3.10 (Production still on 3.9)
from dataclasses import asdict, dataclass, field
import datetime as dt
from django.db import models
class Subject(models.Model):
identification = models.CharField(max_length=200, primary_key=True)
initials = models.CharField(max_length=200, null=True)
name = models.CharField(max_length=200, null=True)
def __str__(self):
return self.name
class Exam(models.Model):
identification = models.CharField(max_length=200, null=True)
date = models.DateField(blank=True, null=True)
time = models.TimeField(blank=True, null=True)
weekday = models.CharField(max_length=200, null=True)
class PartialExam(models.Model):
identification = models.CharField(max_length=200, null=True)
regStudCount = models.CharField(max_length=200, null=True)
subjectIds = models.ManyToManyField(Subject)
exam = models.ForeignKey("Exam", blank=True, null=True, on_delete=models.SET_NULL)
class Lecturer(models.Model):
identification = models.CharField(max_length=200, primary_key=True)
firstName = models.CharField(max_length=200, null=True)
lastName = models.CharField(max_length=200, null=True)
title = models.CharField(max_length=200, null=True)
class Attendance(models.Model):
identification = models.CharField(max_length=200, primary_key=True)
date = models.DateField(blank=True, null=True)
time = models.TimeField(blank=True, null=True)
dateTimeText = models.CharField(max_length=200, null=True)
weekday = models.CharField(max_length=200, null=True)
lecturer = models.ForeignKey(
"Lecturer", blank=True, null=True, on_delete=models.SET_NULL
)
class StudentExam(models.Model):
examIdentification = models.CharField(max_length=200, null=True)
date = models.DateField(blank=True, null=True)
time = models.TimeField(blank=True, null=True)
weekday = models.CharField(max_length=200, null=True)
location = models.CharField(max_length=200, null=True)
examExecution = models.ForeignKey(
"ExamExecution", blank=True, null=True, on_delete=models.CASCADE
)
class Student(models.Model):
matrikel = models.CharField(max_length=200, primary_key=True)
exams = models.ManyToManyField(StudentExam)
class ExamExecution(models.Model):
lecturer = models.ForeignKey(
"Lecturer", blank=True, null=True, on_delete=models.CASCADE
)
supervisorType = models.CharField(max_length=200, null=True)
location = models.CharField(max_length=200, null=True)
subjectIds = models.ManyToManyField(Subject)
partialExam = models.ForeignKey(
"PartialExam", blank=True, null=True, on_delete=models.SET_NULL
)
class Meta:
ordering = ("partialExam__exam__date", "partialExam__exam__time")
# @dataclass()
# class API_ExamDataSet_ForStudent(models.Model):
# date: dt.date
# time: dt.time
# weekday: str
# room: str | None
# location: str | None
# subjectIdent: str | None
# examIdent: str | None
# examStudCount: int | None
# supervisor: str
# studMartNr: str | None
# def to_dict(self):
# return asdict(self)
class API_ExamDataSet_ForStudent(models.Model):
date = models.DateField(blank=True, null=True)
time = models.TimeField(blank=True, null=True)
weekday = models.CharField(max_length=200, null=True)
room = models.CharField(max_length=200, null=True)
location = models.CharField(max_length=200, null=True)
subjectIdent = models.CharField(max_length=200, null=True)
examIdent = models.CharField(max_length=200, null=True)
examStudCount = models.CharField(max_length=200, null=True)
supervisor = models.CharField(max_length=200, null=True)
studMartNr = models.CharField(max_length=200, null=True)
def to_dict(self):
return asdict(self)
@dataclass(order=True)
class ExamLines:
sort_index: dt.datetime = field(init=False)
date: dt.date
time: dt.time
weekday: str
location: str | None
subjectIds: list[Subject] | None
examIdent: str | None
examStudCound: int | None
supervisorType: str
executionSet: list | None
partialExamIdent: str | None
def __post_init__(self):
self.sort_index = dt.datetime.combine(self.date, self.time)
def sort_and_group_datetime(examLines: list):
examLine_Datetime_Groups = {}
for examLine in examLines:
if examLine.sort_index not in examLine_Datetime_Groups:
examLine_Datetime_Groups[examLine.sort_index] = []
examLine_Datetime_Groups[examLine.sort_index].append(examLine)
sorted_groups = sorted(examLine_Datetime_Groups.items(), key=lambda x: x[0])
sorted_result = []
for _, group in sorted_groups:
sorted_result.extend(group)
return sorted_result
+3
View File
@@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.
+13
View File
@@ -0,0 +1,13 @@
from django.urls import path
from . import views
app_name = 'pp_viewer'
urlpatterns = [
path('lecturer', views.lecturer, name='lecturer'),
path('subject', views.subject, name='subject'),
path('exam', views.exam, name='exam'),
path('student', views.student, name='student'),
path('studentExam/<int:student_id>/', views.examsForStudent, name='examForStudent'),
path('lecturerExam/<str:lecturer_id>/', views.examsForLecturer, name='examForLecturer'),
]
+115
View File
@@ -0,0 +1,115 @@
from django.shortcuts import render
from django.template.defaulttags import register
from django.http import Http404
from django.contrib.auth.decorators import login_required
from .models import ExamLines, Lecturer, Subject, Exam, Student, sort_and_group_datetime
import datetime as dt
@login_required
def lecturer(request):
lecturers = Lecturer.objects.all()
context = {"lecturers": lecturers}
return render(request, "pruefplan/lecturer.html", context)
@login_required
def subject(request):
subjects = Subject.objects.all()
context = {"subjects": subjects}
return render(request, "pruefplan/subject.html", context)
@login_required
def student(request):
students = Student.objects.all()
context = {"students": students}
return render(request, "pruefplan/student.html", context)
@login_required
def exam(request):
exams = Exam.objects.all()
supervisorSetDict = {}
for ex in exams:
examSupervisors = []
for partialExam in ex.partialexam_set.all():
for examExe in partialExam.examexecution_set.all():
supervisor = (
examExe.lecturer.firstName + " " + examExe.lecturer.lastName
)
if supervisor not in examSupervisors:
examSupervisors.append(supervisor)
supervisorSetDict[ex.identification] = examSupervisors
context = {"exams": exams, "supervisorSetDict": supervisorSetDict}
return render(request, "pruefplan/exam.html", context)
@register.filter
def get_item(dictionary, key):
return dictionary.get(key)
def examsForLecturer(request, lecturer_id):
lecturer = Lecturer.objects.filter(pk=lecturer_id).first()
if lecturer is not None:
lecExamExes = lecturer.examexecution_set.all()
lecAttendance = lecturer.attendance_set.all()
lecExamLines = mergeModels(lecExamExes, lecAttendance)
context = {
"lecturer": lecturer,
"lecExamLines": lecExamLines,
"lecExamExes": lecExamExes,
}
return render(request, "pruefplan/lecturerExam.html", context)
else:
raise Http404("Dozentenkennung ungültig.")
def examsForStudent(request, student_id):
student = Student.objects.all().filter(matrikel=student_id).first()
if student is not None:
exams = student.exams.all()
context = {"student": student, "exams": exams}
return render(request, "pruefplan/studentExam.html", context)
else:
raise Http404("Matrikelnummer ungültig.")
def mergeModels(lecExamExes, lecAttendance):
result = [
ExamLines(
date=examExes.partialExam.exam.date,
time=examExes.partialExam.exam.time,
weekday=examExes.partialExam.exam.weekday,
location=examExes.location,
subjectIds=examExes.subjectIds,
examIdent=examExes.partialExam.identification,
examStudCound=examExes.partialExam.regStudCount,
supervisorType=examExes.supervisorType,
executionSet=list(examExes.partialExam.examexecution_set.all()),
partialExamIdent=examExes.partialExam.exam.identification,
)
for examExes in lecExamExes
]
result += [
ExamLines(
date=attendance.date,
time=attendance.time,
weekday=attendance.weekday,
location=None,
subjectIds=None,
examIdent=None,
examStudCound=None,
supervisorType="PRÄSENZ",
executionSet=None,
partialExamIdent=None,
)
for attendance in lecAttendance
]
result = sort_and_group_datetime(result)
return result
+49
View File
@@ -0,0 +1,49 @@
pyasn1>=0.3.7
Django>=2
ldap3>=2.3
openpyxl>=2.4.8
pytz>=2018.7
asgiref>=3.7.2
boto3>=1.20.26
botocore>=1.23.54
certifi>=2023.11.17
cffi>=1.16.0
charset-normalizer>=3.3.2
cryptography>=41.0.7
dj-database-url>=2.1.0
Django>=4.2.7
django-anymail>=10.2
django-cors-headers>=3.14.0
django-jazzmin>=2.6.0
django-storages>=1.12.3
django-ckeditor-5
djangorestframework>=3.14.0
djangorestframework-simplejwt>=5.2.2
drf-yasg>=1.21.7
environs>=10.0.0
gunicorn>=21.2.0
idna>=3.6
inflection>=0.5.1
jmespath>=0.10.0
marshmallow>=3.20.1
packaging>=23.2
psycopg2>=2.9.9
pycparser>=2.21
PyJWT>=2.6.0
python-dateutil>=2.8.2
python-dotenv>=1.0.0
pytz>=2023.3.post1
PyYAML>=6.0.1
requests>=2.31.0
s3transfer>=0.5.2
shortuuid>=1.0.11
six>=1.16.0
sqlparse>=0.4.4
stripe>=7.9.0
typing_extensions>=4.9.0
tzdata>=2023.3
uritemplate>=4.1.1
urllib3>=1.26.18
requests
File diff suppressed because it is too large. Load diff
@@ -0,0 +1 @@
{"version":3,"sources":["../../scss/bootstrap-grid.scss","bootstrap-grid.css","../../scss/_grid.scss","../../scss/mixins/_grid.scss","../../scss/mixins/_breakpoints.scss","../../scss/_variables.scss","../../scss/mixins/_grid-framework.scss","../../scss/utilities/_flex.scss"],"names":[],"mappings":"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 truncated
+7
View File
@@ -0,0 +1,7 @@
/*!
* Bootstrap Grid v4.0.0-beta.2 (https://getbootstrap.com)
* Copyright 2011-2017 The Bootstrap Authors
* Copyright 2011-2017 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
*/@-ms-viewport{width:device-width}html{box-sizing:border-box;-ms-overflow-style:scrollbar}*,::after,::before{box-sizing:inherit}.container{width:100%;padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}@media (min-width:576px){.container{max-width:540px}}@media (min-width:768px){.container{max-width:720px}}@media (min-width:992px){.container{max-width:960px}}@media (min-width:1200px){.container{max-width:1140px}}.container-fluid{width:100%;padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}.row{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;margin-right:-15px;margin-left:-15px}.no-gutters{margin-right:0;margin-left:0}.no-gutters>.col,.no-gutters>[class*=col-]{padding-right:0;padding-left:0}.col,.col-1,.col-10,.col-11,.col-12,.col-2,.col-3,.col-4,.col-5,.col-6,.col-7,.col-8,.col-9,.col-auto,.col-lg,.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-auto,.col-md,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-auto,.col-sm,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-auto,.col-xl,.col-xl-1,.col-xl-10,.col-xl-11,.col-xl-12,.col-xl-2,.col-xl-3,.col-xl-4,.col-xl-5,.col-xl-6,.col-xl-7,.col-xl-8,.col-xl-9,.col-xl-auto{position:relative;width:100%;min-height:1px;padding-right:15px;padding-left:15px}.col{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:none}.col-1{-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-2{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-4{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-5{-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-7{-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-8{-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-10{-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-11{-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-first{-ms-flex-order:-1;order:-1}.order-1{-ms-flex-order:1;order:1}.order-2{-ms-flex-order:2;order:2}.order-3{-ms-flex-order:3;order:3}.order-4{-ms-flex-order:4;order:4}.order-5{-ms-flex-order:5;order:5}.order-6{-ms-flex-order:6;order:6}.order-7{-ms-flex-order:7;order:7}.order-8{-ms-flex-order:8;order:8}.order-9{-ms-flex-order:9;order:9}.order-10{-ms-flex-order:10;order:10}.order-11{-ms-flex-order:11;order:11}.order-12{-ms-flex-order:12;order:12}.offset-1{margin-left:8.333333%}.offset-2{margin-left:16.666667%}.offset-3{margin-left:25%}.offset-4{margin-left:33.333333%}.offset-5{margin-left:41.666667%}.offset-6{margin-left:50%}.offset-7{margin-left:58.333333%}.offset-8{margin-left:66.666667%}.offset-9{margin-left:75%}.offset-10{margin-left:83.333333%}.offset-11{margin-left:91.666667%}@media (min-width:576px){.col-sm{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-sm-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:none}.col-sm-1{-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-sm-2{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-sm-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-sm-4{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-sm-5{-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-sm-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-sm-7{-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-sm-8{-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-sm-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-sm-10{-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-sm-11{-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-sm-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-sm-first{-ms-flex-order:-1;order:-1}.order-sm-1{-ms-flex-order:1;order:1}.order-sm-2{-ms-flex-order:2;order:2}.order-sm-3{-ms-flex-order:3;order:3}.order-sm-4{-ms-flex-order:4;order:4}.order-sm-5{-ms-flex-order:5;order:5}.order-sm-6{-ms-flex-order:6;order:6}.order-sm-7{-ms-flex-order:7;order:7}.order-sm-8{-ms-flex-order:8;order:8}.order-sm-9{-ms-flex-order:9;order:9}.order-sm-10{-ms-flex-order:10;order:10}.order-sm-11{-ms-flex-order:11;order:11}.order-sm-12{-ms-flex-order:12;order:12}.offset-sm-0{margin-left:0}.offset-sm-1{margin-left:8.333333%}.offset-sm-2{margin-left:16.666667%}.offset-sm-3{margin-left:25%}.offset-sm-4{margin-left:33.333333%}.offset-sm-5{margin-left:41.666667%}.offset-sm-6{margin-left:50%}.ofLine truncated
/*# sourceMappingURL=bootstrap-grid.min.css.map */
@@ -0,0 +1 @@
{"version":3,"sources":["../../scss/bootstrap-grid.scss","dist/css/bootstrap-grid.css","../../scss/_grid.scss","../../scss/mixins/_grid.scss","../../scss/mixins/_breakpoints.scss","../../scss/mixins/_grid-framework.scss","../../scss/utilities/_flex.scss"],"names":[],"mappings":"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 truncated
+342
View File
@@ -0,0 +1,342 @@
/*!
* Bootstrap Reboot v4.0.0-beta.2 (https://getbootstrap.com)
* Copyright 2011-2017 The Bootstrap Authors
* Copyright 2011-2017 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
*/
*,
*::before,
*::after {
box-sizing: border-box;
}
html {
font-family: sans-serif;
line-height: 1.15;
-webkit-text-size-adjust: 100%;
-ms-text-size-adjust: 100%;
-ms-overflow-style: scrollbar;
-webkit-tap-highlight-color: transparent;
}
@-ms-viewport {
width: device-width;
}
article, aside, dialog, figcaption, figure, footer, header, hgroup, main, nav, section {
display: block;
}
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
font-size: 1rem;
font-weight: 400;
line-height: 1.5;
color: #212529;
text-align: left;
background-color: #fff;
}
[tabindex="-1"]:focus {
outline: none !important;
}
hr {
box-sizing: content-box;
height: 0;
overflow: visible;
}
h1, h2, h3, h4, h5, h6 {
margin-top: 0;
margin-bottom: 0.5rem;
}
p {
margin-top: 0;
margin-bottom: 1rem;
}
abbr[title],
abbr[data-original-title] {
text-decoration: underline;
-webkit-text-decoration: underline dotted;
text-decoration: underline dotted;
cursor: help;
border-bottom: 0;
}
address {
margin-bottom: 1rem;
font-style: normal;
line-height: inherit;
}
ol,
ul,
dl {
margin-top: 0;
margin-bottom: 1rem;
}
ol ol,
ul ul,
ol ul,
ul ol {
margin-bottom: 0;
}
dt {
font-weight: 700;
}
dd {
margin-bottom: .5rem;
margin-left: 0;
}
blockquote {
margin: 0 0 1rem;
}
dfn {
font-style: italic;
}
b,
strong {
font-weight: bolder;
}
small {
font-size: 80%;
}
sub,
sup {
position: relative;
font-size: 75%;
line-height: 0;
vertical-align: baseline;
}
sub {
bottom: -.25em;
}
sup {
top: -.5em;
}
a {
color: #007bff;
text-decoration: none;
background-color: transparent;
-webkit-text-decoration-skip: objects;
}
a:hover {
color: #0056b3;
text-decoration: underline;
}
a:not([href]):not([tabindex]) {
color: inherit;
text-decoration: none;
}
a:not([href]):not([tabindex]):focus, a:not([href]):not([tabindex]):hover {
color: inherit;
text-decoration: none;
}
a:not([href]):not([tabindex]):focus {
outline: 0;
}
pre,
code,
kbd,
samp {
font-family: monospace, monospace;
font-size: 1em;
}
pre {
margin-top: 0;
margin-bottom: 1rem;
overflow: auto;
-ms-overflow-style: scrollbar;
}
figure {
margin: 0 0 1rem;
}
img {
vertical-align: middle;
border-style: none;
}
svg:not(:root) {
overflow: hidden;
}
a,
area,
button,
[role="button"],
input:not([type="range"]),
label,
select,
summary,
textarea {
-ms-touch-action: manipulation;
touch-action: manipulation;
}
table {
border-collapse: collapse;
}
caption {
padding-top: 0.75rem;
padding-bottom: 0.75rem;
color: #868e96;
text-align: left;
caption-side: bottom;
}
th {
text-align: inherit;
}
label {
display: inline-block;
margin-bottom: .5rem;
}
button {
border-radius: 0;
}
button:focus {
outline: 1px dotted;
outline: 5px auto -webkit-focus-ring-color;
}
input,
button,
select,
optgroup,
textarea {
margin: 0;
font-family: inherit;
font-size: inherit;
line-height: inherit;
}
button,
input {
overflow: visible;
}
button,
select {
text-transform: none;
}
button,
html [type="button"],
[type="reset"],
[type="submit"] {
-webkit-appearance: button;
}
button::-moz-focus-inner,
[type="button"]::-moz-focus-inner,
[type="reset"]::-moz-focus-inner,
[type="submit"]::-moz-focus-inner {
padding: 0;
border-style: none;
}
input[type="radio"],
input[type="checkbox"] {
box-sizing: border-box;
padding: 0;
}
input[type="date"],
input[type="time"],
input[type="datetime-local"],
input[type="month"] {
-webkit-appearance: listbox;
}
textarea {
overflow: auto;
resize: vertical;
}
fieldset {
min-width: 0;
padding: 0;
margin: 0;
border: 0;
}
legend {
display: block;
width: 100%;
max-width: 100%;
padding: 0;
margin-bottom: .5rem;
font-size: 1.5rem;
line-height: inherit;
color: inherit;
white-space: normal;
}
progress {
vertical-align: baseline;
}
[type="number"]::-webkit-inner-spin-button,
[type="number"]::-webkit-outer-spin-button {
height: auto;
}
[type="search"] {
outline-offset: -2px;
-webkit-appearance: none;
}
[type="search"]::-webkit-search-cancel-button,
[type="search"]::-webkit-search-decoration {
-webkit-appearance: none;
}
::-webkit-file-upload-button {
font: inherit;
-webkit-appearance: button;
}
output {
display: inline-block;
}
summary {
display: list-item;
}
template {
display: none;
}
[hidden] {
display: none !important;
}
/*# sourceMappingURL=bootstrap-reboot.css.map */
@@ -0,0 +1 @@
{"version":3,"sources":["../../scss/bootstrap-reboot.scss","../../scss/_reboot.scss","bootstrap-reboot.css","../../scss/_variables.scss","../../scss/mixins/_hover.scss"],"names":[],"mappings":"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","file":"bootstrap-reboot.css","sourcesContent":["/*!\n * Bootstrap Reboot v4.0.0-beta.2 (https://getbootstrap.com)\n * Copyright 2011-2017 The Bootstrap Authors\n * Copyright 2011-2017 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)\n */\n\n@import \"functions\";\n@import \"variables\";\n@import \"mixins\";\n@import \"reboot\";\n","// stylelint-disable at-rule-no-vendor-prefix, declaration-no-important, selector-no-qualifying-type, property-no-vendor-prefix\n\n// Reboot\n//\n// Normalization of HTML elements, manually forked from Normalize.css to remove\n// styles targeting irrelevant browsers while applying new styles.\n//\n// Normalize is licensed MIT. https://github.com/necolas/normalize.css\n\n\n// Document\n//\n// 1. Change from `box-sizing: content-box` so that `width` is not affected by `padding` or `border`.\n// 2. Change the default font family in all browsers.\n// 3. Correct the line height in all browsers.\n// 4. Prevent adjustments of font size after orientation changes in IE on Windows Phone and in iOS.\n// 5. Setting @viewport causes scrollbars to overlap content in IE11 and Edge, so\n// we force a non-overlapping, non-auto-hiding scrollbar to counteract.\n// 6. Change the default tap highlight to be completely transparent in iOS.\n\n*,\n*::before,\n*::after {\n box-sizing: border-box; // 1\n}\n\nhtml {\n font-family: sans-serif; // 2\n line-height: 1.15; // 3\n -webkit-text-size-adjust: 100%; // 4\n -ms-text-size-adjust: 100%; // 4\n -ms-overflow-style: scrollbar; // 5\n -webkit-tap-highlight-color: rgba(0,0,0,0); // 6\n}\n\n// IE10+ doesn't honor `<meta name=\"viewport\">` in some cases.\n@at-root {\n @-ms-viewport {\n width: device-width;\n }\n}\n\n// stylelint-disable selector-list-comma-newline-after\n// Shim for \"new\" HTML5 structural elements to display correctly (IE10, older browsers)\narticle, aside, dialog, figcaption, figure, footer, header, hgroup, main, nav, section {\n display: block;\n}\n// stylelint-enable selector-list-comma-newline-after\n\n// Body\n//\n// 1. Remove the margin in all browsers.\n// 2. As a best practice, apply a default `background-color`.\n// 3. Set an explicit initial text-align value so that we can later use the\n// the `inherit` value on things like `<th>` elements.\n\nbody {\n margin: 0; // 1\n font-family: $font-family-base;\n font-size: $font-size-base;\n font-weight: $font-weight-base;\n line-height: $line-heiLine truncated
+8
View File
@@ -0,0 +1,8 @@
/*!
* Bootstrap Reboot v4.0.0-beta.2 (https://getbootstrap.com)
* Copyright 2011-2017 The Bootstrap Authors
* Copyright 2011-2017 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
*/*,::after,::before{box-sizing:border-box}html{font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;-ms-overflow-style:scrollbar;-webkit-tap-highlight-color:transparent}@-ms-viewport{width:device-width}article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";font-size:1rem;font-weight:400;line-height:1.5;color:#212529;text-align:left;background-color:#fff}[tabindex="-1"]:focus{outline:0!important}hr{box-sizing:content-box;height:0;overflow:visible}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem}p{margin-top:0;margin-bottom:1rem}abbr[data-original-title],abbr[title]{text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;border-bottom:0}address{margin-bottom:1rem;font-style:normal;line-height:inherit}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}dfn{font-style:italic}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#007bff;text-decoration:none;background-color:transparent;-webkit-text-decoration-skip:objects}a:hover{color:#0056b3;text-decoration:underline}a:not([href]):not([tabindex]){color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus,a:not([href]):not([tabindex]):hover{color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus{outline:0}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}pre{margin-top:0;margin-bottom:1rem;overflow:auto;-ms-overflow-style:scrollbar}figure{margin:0 0 1rem}img{vertical-align:middle;border-style:none}svg:not(:root){overflow:hidden}[role=button],a,area,button,input:not([type=range]),label,select,summary,textarea{-ms-touch-action:manipulation;touch-action:manipulation}table{border-collapse:collapse}caption{padding-top:.75rem;padding-bottom:.75rem;color:#868e96;text-align:left;caption-side:bottom}th{text-align:inherit}label{display:inline-block;margin-bottom:.5rem}button{border-radius:0}button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,input{overflow:visible}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{padding:0;border-style:none}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=date],input[type=datetime-local],input[type=month],input[type=time]{-webkit-appearance:listbox}textarea{overflow:auto;resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;max-width:100%;padding:0;margin-bottom:.5rem;font-size:1.5rem;line-height:inherit;color:inherit;white-space:normal}progress{vertical-align:baseline}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:none}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}summary{display:list-item}template{display:none}[hidden]{display:none!important}
/*# sourceMappingURL=bootstrap-reboot.min.css.map */
@@ -0,0 +1 @@
{"version":3,"sources":["../../scss/bootstrap-reboot.scss","../../scss/_reboot.scss","dist/css/bootstrap-reboot.css","bootstrap-reboot.css","../../scss/mixins/_hover.scss"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Bootstrap Reboot v4.0.0-beta.2 (https://getbootstrap.com)\n * Copyright 2011-2017 The Bootstrap Authors\n * Copyright 2011-2017 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)\n */\n\n@import \"functions\";\n@import \"variables\";\n@import \"mixins\";\n@import \"reboot\";\n","// stylelint-disable at-rule-no-vendor-prefix, declaration-no-important, selector-no-qualifying-type, property-no-vendor-prefix\n\n// Reboot\n//\n// Normalization of HTML elements, manually forked from Normalize.css to remove\n// styles targeting irrelevant browsers while applying new styles.\n//\n// Normalize is licensed MIT. https://github.com/necolas/normalize.css\n\n\n// Document\n//\n// 1. Change from `box-sizing: content-box` so that `width` is not affected by `padding` or `border`.\n// 2. Change the default font family in all browsers.\n// 3. Correct the line height in all browsers.\n// 4. Prevent adjustments of font size after orientation changes in IE on Windows Phone and in iOS.\n// 5. Setting @viewport causes scrollbars to overlap content in IE11 and Edge, so\n// we force a non-overlapping, non-auto-hiding scrollbar to counteract.\n// 6. Change the default tap highlight to be completely transparent in iOS.\n\n*,\n*::before,\n*::after {\n box-sizing: border-box; // 1\n}\n\nhtml {\n font-family: sans-serif; // 2\n line-height: 1.15; // 3\n -webkit-text-size-adjust: 100%; // 4\n -ms-text-size-adjust: 100%; // 4\n -ms-overflow-style: scrollbar; // 5\n -webkit-tap-highlight-color: rgba(0,0,0,0); // 6\n}\n\n// IE10+ doesn't honor `<meta name=\"viewport\">` in some cases.\n@at-root {\n @-ms-viewport {\n width: device-width;\n }\n}\n\n// stylelint-disable selector-list-comma-newline-after\n// Shim for \"new\" HTML5 structural elements to display correctly (IE10, older browsers)\narticle, aside, dialog, figcaption, figure, footer, header, hgroup, main, nav, section {\n display: block;\n}\n// stylelint-enable selector-list-comma-newline-after\n\n// Body\n//\n// 1. Remove the margin in all browsers.\n// 2. As a best practice, apply a default `background-color`.\n// 3. Set an explicit initial text-align value so that we can later use the\n// the `inherit` value on things like `<th>` elements.\n\nbody {\n margin: 0; // 1\n font-family: $font-family-base;\n font-size: $font-size-base;\n font-weight: $font-weight-base;\n line-height: $line-height-base;\n color: $body-color;\n text-align: left; // 3\n background-color: $body-bg; // 2\n}\n\n// Suppress the focus outline on elements that cannot be accessed via keyboard.\n// This prevents aLine truncated
File diff suppressed because it is too large. Load diff
@@ -0,0 +1 @@
{"version":3,"sources":["../../scss/bootstrap.scss","../../scss/_root.scss","../../scss/_print.scss","bootstrap.css","../../scss/_reboot.scss","../../scss/_variables.scss","../../scss/mixins/_hover.scss","../../scss/_type.scss","../../scss/mixins/_lists.scss","../../scss/_images.scss","../../scss/mixins/_image.scss","../../scss/mixins/_border-radius.scss","../../scss/mixins/_transition.scss","../../scss/_code.scss","../../scss/_grid.scss","../../scss/mixins/_grid.scss","../../scss/mixins/_breakpoints.scss","../../scss/mixins/_grid-framework.scss","../../scss/_tables.scss","../../scss/mixins/_table-row.scss","../../scss/_functions.scss","../../scss/_forms.scss","../../scss/mixins/_forms.scss","../../scss/_buttons.scss","../../scss/mixins/_buttons.scss","../../scss/mixins/_gradients.scss","../../scss/_transitions.scss","../../scss/_dropdown.scss","../../scss/mixins/_caret.scss","../../scss/mixins/_nav-divider.scss","../../scss/_button-group.scss","../../scss/_input-group.scss","../../scss/_custom-forms.scss","../../scss/_nav.scss","../../scss/_navbar.scss","../../scss/_card.scss","../../scss/_breadcrumb.scss","../../scss/_pagination.scss","../../scss/mixins/_pagination.scss","../../scss/_badge.scss","../../scss/mixins/_badge.scss","../../scss/_jumbotron.scss","../../scss/_alert.scss","../../scss/mixins/_alert.scss","../../scss/_progress.scss","../../scss/_media.scss","../../scss/_list-group.scss","../../scss/mixins/_list-group.scss","../../scss/_close.scss","../../scss/_modal.scss","../../scss/_tooltip.scss","../../scss/mixins/_reset-text.scss","../../scss/_popover.scss","../../scss/_carousel.scss","../../scss/utilities/_align.scss","../../scss/mixins/_background-variant.scss","../../scss/utilities/_background.scss","../../scss/utilities/_borders.scss","../../scss/mixins/_clearfix.scss","../../scss/utilities/_display.scss","../../scss/utilities/_embed.scss","../../scss/utilities/_flex.scss","../../scss/utilities/_float.scss","../../scss/mixins/_float.scss","../../scss/utilities/_position.scss","../../scss/utilities/_screenreaders.scss","../../scss/mixins/_screen-reader.scss","../../scss/utilities/_sizing.scss","../../scss/utilities/_spacing.scss","../../scss/utilities/_text.scss","../../scss/mixins/_text-truncate.scss","../../scss/mixins/_text-emphasis.scss","../../scss/mixins/_text-hide.scss","../../scss/utilities/_visibility.scss","../../scss/mixins/_visibility.scss"],"names":[],"mappings":"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 truncated
+7
View File
@@ -0,0 +1,7 @@
/*!
* Bootstrap v4.0.0-beta.2 (https://getbootstrap.com)
* Copyright 2011-2017 The Bootstrap Authors
* Copyright 2011-2017 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
*/:root{--blue:#007bff;--indigo:#6610f2;--purple:#6f42c1;--pink:#e83e8c;--red:#dc3545;--orange:#fd7e14;--yellow:#ffc107;--green:#28a745;--teal:#20c997;--cyan:#17a2b8;--white:#fff;--gray:#868e96;--gray-dark:#343a40;--primary:#007bff;--secondary:#868e96;--success:#28a745;--info:#17a2b8;--warning:#ffc107;--danger:#dc3545;--light:#f8f9fa;--dark:#343a40;--breakpoint-xs:0;--breakpoint-sm:576px;--breakpoint-md:768px;--breakpoint-lg:992px;--breakpoint-xl:1200px;--font-family-sans-serif:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";--font-family-monospace:"SFMono-Regular",Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace}@media print{*,::after,::before{text-shadow:none!important;box-shadow:none!important}a,a:visited{text-decoration:underline}abbr[title]::after{content:" (" attr(title) ")"}pre{white-space:pre-wrap!important}blockquote,pre{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}.navbar{display:none}.badge{border:1px solid #000}.table{border-collapse:collapse!important}.table td,.table th{background-color:#fff!important}.table-bordered td,.table-bordered th{border:1px solid #ddd!important}}*,::after,::before{box-sizing:border-box}html{font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;-ms-overflow-style:scrollbar;-webkit-tap-highlight-color:transparent}@-ms-viewport{width:device-width}article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";font-size:1rem;font-weight:400;line-height:1.5;color:#212529;text-align:left;background-color:#fff}[tabindex="-1"]:focus{outline:0!important}hr{box-sizing:content-box;height:0;overflow:visible}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem}p{margin-top:0;margin-bottom:1rem}abbr[data-original-title],abbr[title]{text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;border-bottom:0}address{margin-bottom:1rem;font-style:normal;line-height:inherit}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}dfn{font-style:italic}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#007bff;text-decoration:none;background-color:transparent;-webkit-text-decoration-skip:objects}a:hover{color:#0056b3;text-decoration:underline}a:not([href]):not([tabindex]){color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus,a:not([href]):not([tabindex]):hover{color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus{outline:0}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}pre{margin-top:0;margin-bottom:1rem;overflow:auto;-ms-overflow-style:scrollbar}figure{margin:0 0 1rem}img{vertical-align:middle;border-style:none}svg:not(:root){overflow:hidden}[role=button],a,area,button,input:not([type=range]),label,select,summary,textarea{-ms-touch-action:manipulation;touch-action:manipulation}table{border-collapse:collapse}caption{padding-top:.75rem;padding-bottom:.75rem;color:#868e96;text-align:left;caption-side:bottom}th{text-align:inherit}label{display:inline-block;margin-bottom:.5rem}button{border-radius:0}button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,input{overflow:visible}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{padding:0;border-style:none}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=date],input[type=datetime-local],input[type=month],input[type=time]{-webkit-appearance:listbox}textarea{overflow:auto;resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;max-width:100%;padding:0;margin-bottom:.5rem;font-size:1.5rem;line-height:inherit;color:inherit;white-space:normal}progress{vertical-align:baseline}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:none}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}summary{display:list-item}template{display:none}[hidden]{display:none!imLine truncated
/*# sourceMappingURL=bootstrap.min.css.map */
@@ -0,0 +1 @@
{"version":3,"sources":["../../scss/bootstrap.scss","../../scss/_root.scss","../../scss/_print.scss","dist/css/bootstrap.css","../../scss/_reboot.scss","bootstrap.css","../../scss/mixins/_hover.scss","../../scss/_type.scss","../../scss/mixins/_lists.scss","../../scss/_images.scss","../../scss/mixins/_image.scss","../../scss/mixins/_border-radius.scss","../../scss/mixins/_transition.scss","../../scss/_code.scss","../../scss/_grid.scss","../../scss/mixins/_grid.scss","../../scss/mixins/_breakpoints.scss","../../scss/mixins/_grid-framework.scss","../../scss/_tables.scss","../../scss/mixins/_table-row.scss","../../scss/_forms.scss","../../scss/mixins/_forms.scss","../../scss/_buttons.scss","../../scss/mixins/_buttons.scss","../../scss/mixins/_gradients.scss","../../scss/_transitions.scss","../../scss/_dropdown.scss","../../scss/mixins/_caret.scss","../../scss/mixins/_nav-divider.scss","../../scss/_button-group.scss","../../scss/_input-group.scss","../../scss/_custom-forms.scss","../../scss/_nav.scss","../../scss/_navbar.scss","../../scss/_card.scss","../../scss/_breadcrumb.scss","../../scss/_pagination.scss","../../scss/mixins/_pagination.scss","../../scss/_badge.scss","../../scss/mixins/_badge.scss","../../scss/_jumbotron.scss","../../scss/_alert.scss","../../scss/mixins/_alert.scss","../../scss/_progress.scss","../../scss/_media.scss","../../scss/_list-group.scss","../../scss/mixins/_list-group.scss","../../scss/_close.scss","../../scss/_modal.scss","../../scss/_tooltip.scss","../../scss/mixins/_reset-text.scss","../../scss/_popover.scss","../../scss/_carousel.scss","../../scss/utilities/_align.scss","../../scss/mixins/_background-variant.scss","../../scss/utilities/_background.scss","../../scss/utilities/_borders.scss","../../scss/mixins/_clearfix.scss","../../scss/utilities/_display.scss","../../scss/utilities/_embed.scss","../../scss/utilities/_flex.scss","../../scss/utilities/_float.scss","../../scss/mixins/_float.scss","../../scss/utilities/_position.scss","../../scss/utilities/_screenreaders.scss","../../scss/mixins/_screen-reader.scss","../../scss/utilities/_sizing.scss","../../scss/utilities/_spacing.scss","../../scss/utilities/_text.scss","../../scss/mixins/_text-truncate.scss","../../scss/mixins/_text-emphasis.scss","../../scss/mixins/_text-hide.scss","../../scss/utilities/_visibility.scss","../../scss/mixins/_visibility.scss"],"names":[],"mappings":"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 truncated
File diff suppressed because it is too large. Load diff
@@ -0,0 +1 @@
{"version":3,"file":"bootstrap.bundle.js","sources":["../../js/src/util.js","../../js/src/alert.js","../../js/src/button.js","../../js/src/carousel.js","../../js/src/collapse.js","../../node_modules/popper.js/dist/esm/popper.js","../../js/src/dropdown.js","../../js/src/modal.js","../../js/src/tooltip.js","../../js/src/popover.js","../../js/src/scrollspy.js","../../js/src/tab.js","../../js/src/index.js"],"sourcesContent":["import $ from 'jquery'\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap (v4.0.0-beta.2): util.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nconst Util = (() => {\n\n\n /**\n * ------------------------------------------------------------------------\n * Private TransitionEnd Helpers\n * ------------------------------------------------------------------------\n */\n\n let transition = false\n\n const MAX_UID = 1000000\n\n const TransitionEndEvent = {\n WebkitTransition : 'webkitTransitionEnd',\n MozTransition : 'transitionend',\n OTransition : 'oTransitionEnd otransitionend',\n transition : 'transitionend'\n }\n\n // shoutout AngusCroll (https://goo.gl/pxwQGp)\n function toType(obj) {\n return {}.toString.call(obj).match(/\\s([a-zA-Z]+)/)[1].toLowerCase()\n }\n\n function getSpecialTransitionEndEvent() {\n return {\n bindType: transition.end,\n delegateType: transition.end,\n handle(event) {\n if ($(event.target).is(this)) {\n return event.handleObj.handler.apply(this, arguments) // eslint-disable-line prefer-rest-params\n }\n return undefined // eslint-disable-line no-undefined\n }\n }\n }\n\n function transitionEndTest() {\n if (window.QUnit) {\n return false\n }\n\n const el = document.createElement('bootstrap')\n\n for (const name in TransitionEndEvent) {\n if (typeof el.style[name] !== 'undefined') {\n return {\n end: TransitionEndEvent[name]\n }\n }\n }\n\n return false\n }\n\n function transitionEndEmulator(duration) {\n let called = false\n\n $(this).one(Util.TRANSITION_END, () => {\n called = true\n })\n\n setTimeout(() => {\n if (!called) {\n Util.triggerTransitionEnd(this)\n }\n }, duration)\n\n return this\n }\n\n function setTransitionEndSupport() {\n transition = transitionEndTest()\n\n $.fn.emulateTransitionEnd = transitionEndEmulator\n\n if (Util.supportsTransitionEnd()) {\n $.event.special[Util.TRANSITION_END] = getSpecialTransitionEndEvent()\n }\n }\n\n\n /**\n * --------------------------------------------------------------------------\n * Public Util Api\n * --------------------------------------------------------------------------\n */\n\n const Util = {\n\n TRANSITION_END: 'bsTransitionEnd',\n\n getUID(prefix) {\n do {\n // eslint-disable-next-line no-bitwise\n prefix += ~~(Math.random() * MAX_UID) // \"~~\" acts like a faster Math.floor() here\n } while (document.getElementById(prefix))\n return prefix\n },\n\n getSelectorFromElement(element) {\n let selector = element.getAttribute('data-target')\n if (!selector || selector === '#') {\n selector = element.getAttribute('href') || ''\n }\n\n try {\n const $selector = $(document).find(selector)\n return $selector.length > 0 ? selector : null\n } catch (error) {\n return null\n }\n },\n\n reflow(element) {\n return element.offsetHeight\n },\n\n triggerTransitionEnd(element) {\n $(element).trigger(transition.end)\n },\n\n supportsTransitionEnd() {\n return Boolean(transition)\n },\n\n isElement(obj) {\n return (obj[0] || obj).nodeType\n },\n\n typeCheckConfig(componentName, config, configTypes) {\n for (const property in configTypes) {\n if (Object.prototype.hasOwnProperty.call(configTypes, property)) {\n const expectedTypes = configTypes[property]\n const value = config[property]\n const valueType = value && Util.isElement(value) ?\n 'element' : toType(value)\n\n if (!new RegExp(expectedTypes).test(valueType)) {\n throw new Error(\n `${componentName.toUpperCase()}: ` +\n `Option \"${property}\" provided type \"${valueType}\" ` +\n `but expected type \"${expectedTypes}\".`)\n }\n }\n }\n }\n }\n\n setTransitionEndSupport()\n\n return Util\n\n})($)\n\nexport default Util\n","import $ from 'jquery'\nimport Util from './util'\n\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap (v4.0.0-beta.2): alert.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/masLine truncated
+7
View File
@@ -0,0 +1,7 @@
/*!
* Bootstrap v4.0.0-beta.2 (https://getbootstrap.com)
* Copyright 2011-2017 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
*/
var bootstrap=function(t,e){"use strict";function n(t,e){for(var n=0;n<e.length;n++){var i=e[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(t,i.key,i)}}function i(t){return t&&"[object Function]"==={}.toString.call(t)}function r(t,e){if(1!==t.nodeType)return[];var n=window.getComputedStyle(t,null);return e?n[e]:n}function o(t){return"HTML"===t.nodeName?t:t.parentNode||t.host}function s(t){if(!t||-1!==["HTML","BODY","#document"].indexOf(t.nodeName))return window.document.body;var e=r(t),n=e.overflow,i=e.overflowX;return/(auto|scroll)/.test(n+e.overflowY+i)?t:s(o(t))}function a(t){var e=t&&t.offsetParent,n=e&&e.nodeName;return n&&"BODY"!==n&&"HTML"!==n?-1!==["TD","TABLE"].indexOf(e.nodeName)&&"static"===r(e,"position")?a(e):e:window.document.documentElement}function l(t){var e=t.nodeName;return"BODY"!==e&&("HTML"===e||a(t.firstElementChild)===t)}function c(t){return null!==t.parentNode?c(t.parentNode):t}function f(t,e){if(!(t&&t.nodeType&&e&&e.nodeType))return window.document.documentElement;var n=t.compareDocumentPosition(e)&Node.DOCUMENT_POSITION_FOLLOWING,i=n?t:e,r=n?e:t,o=document.createRange();o.setStart(i,0),o.setEnd(r,0);var s=o.commonAncestorContainer;if(t!==s&&e!==s||i.contains(r))return l(s)?s:a(s);var h=c(t);return h.host?f(h.host,e):f(t,c(e).host)}function h(t){var e="top"===(arguments.length>1&&void 0!==arguments[1]?arguments[1]:"top")?"scrollTop":"scrollLeft",n=t.nodeName;if("BODY"===n||"HTML"===n){var i=window.document.documentElement;return(window.document.scrollingElement||i)[e]}return t[e]}function u(t,e){var n=arguments.length>2&&void 0!==arguments[2]&&arguments[2],i=h(e,"top"),r=h(e,"left"),o=n?-1:1;return t.top+=i*o,t.bottom+=i*o,t.left+=r*o,t.right+=r*o,t}function d(t,e){var n="x"===e?"Left":"Top",i="Left"===n?"Right":"Bottom";return+t["border"+n+"Width"].split("px")[0]+ +t["border"+i+"Width"].split("px")[0]}function p(t,e,n,i){return Math.max(e["offset"+t],e["scroll"+t],n["client"+t],n["offset"+t],n["scroll"+t],lt()?n["offset"+t]+i["margin"+("Height"===t?"Top":"Left")]+i["margin"+("Height"===t?"Bottom":"Right")]:0)}function g(){var t=window.document.body,e=window.document.documentElement,n=lt()&&window.getComputedStyle(e);return{height:p("Height",t,e,n),width:p("Width",t,e,n)}}function m(t){return ut({},t,{right:t.left+t.width,bottom:t.top+t.height})}function _(t){var e={};if(lt())try{e=t.getBoundingClientRect();var n=h(t,"top"),i=h(t,"left");e.top+=n,e.left+=i,e.bottom+=n,e.right+=i}catch(t){}else e=t.getBoundingClientRect();var o={left:e.left,top:e.top,width:e.right-e.left,height:e.bottom-e.top},s="HTML"===t.nodeName?g():{},a=s.width||t.clientWidth||o.right-o.left,l=s.height||t.clientHeight||o.bottom-o.top,c=t.offsetWidth-a,f=t.offsetHeight-l;if(c||f){var u=r(t);c-=d(u,"x"),f-=d(u,"y"),o.width-=c,o.height-=f}return m(o)}function v(t,e){var n=lt(),i="HTML"===e.nodeName,o=_(t),a=_(e),l=s(t),c=r(e),f=+c.borderTopWidth.split("px")[0],h=+c.borderLeftWidth.split("px")[0],d=m({top:o.top-a.top-f,left:o.left-a.left-h,width:o.width,height:o.height});if(d.marginTop=0,d.marginLeft=0,!n&&i){var p=+c.marginTop.split("px")[0],g=+c.marginLeft.split("px")[0];d.top-=f-p,d.bottom-=f-p,d.left-=h-g,d.right-=h-g,d.marginTop=p,d.marginLeft=g}return(n?e.contains(l):e===l&&"BODY"!==l.nodeName)&&(d=u(d,e)),d}function E(t){var e=window.document.documentElement,n=v(t,e),i=Math.max(e.clientWidth,window.innerWidth||0),r=Math.max(e.clientHeight,window.innerHeight||0),o=h(e),s=h(e,"left");return m({top:o-n.top+n.marginTop,left:s-n.left+n.marginLeft,width:i,height:r})}function T(t){var e=t.nodeName;return"BODY"!==e&&"HTML"!==e&&("fixed"===r(t,"position")||T(o(t)))}function b(t,e,n,i){var r={top:0,left:0},a=f(t,e);if("viewport"===i)r=E(a);else{var l=void 0;"scrollParent"===i?"BODY"===(l=s(o(t))).nodeName&&(l=window.document.documentElement):l="window"===i?window.document.documentElement:i;var c=v(l,a);if("HTML"!==l.nodeName||T(a))r=c;else{var h=g(),u=h.height,d=h.width;r.top+=c.top-c.marginTop,r.bottom=u+c.top,r.left+=c.left-c.marginLeft,r.right=d+c.left}}return r.left+=n,r.top+=n,r.right-=n,r.bottom-=n,r}function C(t){return t.width*t.height}function A(t,e,n,i,r){var o=arguments.length>5&&void 0!==arguments[5]?arguments[5]:0;if(-1===t.indexOf("auto"))return t;var s=b(n,i,o,r),a={top:{width:s.width,height:e.top-s.top},right:{width:s.right-e.right,height:s.height},bottom:{width:s.width,height:s.bottom-e.bottom},left:{width:e.left-s.left,height:s.height}},l=Object.keys(a).map(function(t){return ut({key:t},a[t],{area:C(a[t])})}).sort(function(t,e){return e.area-t.area}),c=l.filter(function(t){var e=t.width,i=t.height;return e>=n.clientWidth&&i>=n.clientHeight}),f=c.length>0?c[0].key:l[0].key,h=t.split("-")[1];return f+(h?"-"+h:"")}function I(t,e,n){return v(n,f(e,n))}function O(t){var e=window.getComputedStyle(t),n=parseFloat(e.marginTop)+parseFloat(e.marginBottom),i=parseFloat(e.marginLeft)+parseFloat(e.marginRight);return{width:t.offsetWidth+i,height:t.offsetHeighLine truncated
//# sourceMappingURL=bootstrap.bundle.min.js.map
@@ -0,0 +1 @@
{"version":3,"sources":["../../node_modules/popper.js/dist/esm/popper.js","../../js/src/util.js","../../js/src/alert.js","../../js/src/button.js","../../js/src/carousel.js","../../js/src/collapse.js","../../js/src/dropdown.js","../../js/src/modal.js","../../js/src/tooltip.js","../../js/src/popover.js","../../js/src/scrollspy.js","../../js/src/tab.js","../../js/src/index.js"],"names":["isFunction","functionToCheck","toString","call","getStyleComputedProperty","element","property","nodeType","css","window","getComputedStyle","getParentNode","nodeName","parentNode","host","getScrollParent","indexOf","document","body","_getStyleComputedProp","overflow","overflowX","test","overflowY","getOffsetParent","offsetParent","documentElement","isOffsetContainer","firstElementChild","getRoot","node","findCommonOffsetParent","element1","element2","order","compareDocumentPosition","Node","DOCUMENT_POSITION_FOLLOWING","start","end","range","createRange","setStart","setEnd","commonAncestorContainer","contains","element1root","getScroll","upperSide","arguments","length","undefined","html","scrollingElement","includeScroll","rect","subtract","scrollTop","scrollLeft","modifier","top","bottom","left","right","getBordersSize","styles","axis","sideA","sideB","split","getSize","computedStyle","Math","max","isIE10$1","getWindowSizes","height","width","getClientRect","offsets","_extends","getBoundingClientRect","err","result","sizes","clientWidth","clientHeight","horizScrollbar","offsetWidth","vertScrollbar","offsetHeight","getOffsetRectRelativeToArbitraryNode","children","parent","isIE10","isHTML","childrenRect","parentRect","scrollParent","borderTopWidth","borderLeftWidth","marginTop","marginLeft","getViewportOffsetRectRelativeToArtbitraryNode","relativeOffset","innerWidth","innerHeight","isFixed","getBoundaries","popper","reference","padding","boundariesElement","boundaries","boundariesNode","_getWindowSizes","getArea","_ref","computeAutoPlacement","placement","refRect","rects","sortedAreas","Object","keys","map","key","area","sort","a","b","filteredAreas","filter","_ref2","computedPlacement","variation","getReferenceOffsets","state","getOuterSizes","x","parseFloat","marginBottom","y","marginRight","getOppositePlacement","hash","replace","matched","getPopperOffsets","referenceOffsets","popperRect","popperOffsets","isHoriz","mainSide","secondarySide","measurement","secondaryMeasurement","find","arr","check","Array","prototype","findIndex","prop","value","cur","match","obj","runModifiers","modifiers","data","ends","slice","forEach","function","console","warn","fn","enabled","update","this","isDestroyed","instance","arrowStyles","attributes","flipped","options","flip","originalPlacement","position","isCreated","onUpdate","onCreate","isModifierEnabled","modifierName","some","name","getSupportedPropertyName","prefixes","upperProp","charAt","toUpperCase","i","prefix","toCheck","style","destroy","removeAttribute","disableEventListeners","removeOnDestroy","removeChild","attachToScrollParents","event","callback","scrollParents","isBody","target","addEventListener","passive","push","setupEventListeners","updateBound","scrollElement","eventsEnabled","enableEventListeners","scheduleUpdate","removeEventListeners","removeEventListener","cancelAnimationFrame","isNumeric","n","isNaN","isFinite","setStyles","unit","setAttributes","setAttribute","isModifierRequired","requestingName","requestedName","requesting","isRequired","_requesting","requested","getOppositeVariation","clockwise","counter","index","validPlacements","concat","reverse","toValue","str","parseOffset","offset","basePlacement","useHeight","fragments","frag","trim","divider","search","splitRegex","ops","op","mergeWithPrevious","reduce","index2","Util","toType","toLowerCase","getSpecialTransitionEndEvent","transition","$","is","handleObj","handler","apply","transitionEndTest","QUnit","el","createElement","TransitionEndEvent","transitionEndEmulator","duration","called","one","TRANSITION_END","triggerTransitionEnd","_this","random","getElementById","selector","getAttribute","error","trigger","Boolean","componentName","config","configTypes","hasOwnProperty","expectedTypes","valueType","isElement","RegExp","Error","emulateTransitionEnd","supportsTransitionEnd","special","Alert","NAME","JQUERY_NO_CONFLICT","Event","ClassName","_element","close","rootElement","_getRootElement","_triggerCloseEvent","isDefaultPrevented","_removeElement","dispose","removeData","getSelectorFromElement","closest","ALERT","closeEvent","CLOSE","removeClass","SHOW","hasClass","FADE","_destroyElement","detach","CLOSED","remove","_jQueryInterface","each","$element","_handleDismiss","alertInstance","preventDefault","on","CLICK_DATA_API","DISMISS","Constructor","noConflict","Button","Selector","toggle","triggerChangeEvent","addAriaPressed","DATA_TOGGLE","input","INPUT","type","checked","ACTIVE","activeElement","hasAttribute","classList","focus","toggleClass","DATA_TOGGLE_CARROT","button","BUTTON","FOCUS_BLUR_DATA_API","Line truncated
File diff suppressed because it is too large. Load diff
@@ -0,0 +1 @@
{"version":3,"file":"bootstrap.js","sources":["../../js/src/util.js","../../js/src/alert.js","../../js/src/button.js","../../js/src/carousel.js","../../js/src/collapse.js","../../js/src/dropdown.js","../../js/src/modal.js","../../js/src/tooltip.js","../../js/src/popover.js","../../js/src/scrollspy.js","../../js/src/tab.js","../../js/src/index.js"],"sourcesContent":["import $ from 'jquery'\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap (v4.0.0-beta.2): util.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nconst Util = (() => {\n\n\n /**\n * ------------------------------------------------------------------------\n * Private TransitionEnd Helpers\n * ------------------------------------------------------------------------\n */\n\n let transition = false\n\n const MAX_UID = 1000000\n\n const TransitionEndEvent = {\n WebkitTransition : 'webkitTransitionEnd',\n MozTransition : 'transitionend',\n OTransition : 'oTransitionEnd otransitionend',\n transition : 'transitionend'\n }\n\n // shoutout AngusCroll (https://goo.gl/pxwQGp)\n function toType(obj) {\n return {}.toString.call(obj).match(/\\s([a-zA-Z]+)/)[1].toLowerCase()\n }\n\n function getSpecialTransitionEndEvent() {\n return {\n bindType: transition.end,\n delegateType: transition.end,\n handle(event) {\n if ($(event.target).is(this)) {\n return event.handleObj.handler.apply(this, arguments) // eslint-disable-line prefer-rest-params\n }\n return undefined // eslint-disable-line no-undefined\n }\n }\n }\n\n function transitionEndTest() {\n if (window.QUnit) {\n return false\n }\n\n const el = document.createElement('bootstrap')\n\n for (const name in TransitionEndEvent) {\n if (typeof el.style[name] !== 'undefined') {\n return {\n end: TransitionEndEvent[name]\n }\n }\n }\n\n return false\n }\n\n function transitionEndEmulator(duration) {\n let called = false\n\n $(this).one(Util.TRANSITION_END, () => {\n called = true\n })\n\n setTimeout(() => {\n if (!called) {\n Util.triggerTransitionEnd(this)\n }\n }, duration)\n\n return this\n }\n\n function setTransitionEndSupport() {\n transition = transitionEndTest()\n\n $.fn.emulateTransitionEnd = transitionEndEmulator\n\n if (Util.supportsTransitionEnd()) {\n $.event.special[Util.TRANSITION_END] = getSpecialTransitionEndEvent()\n }\n }\n\n\n /**\n * --------------------------------------------------------------------------\n * Public Util Api\n * --------------------------------------------------------------------------\n */\n\n const Util = {\n\n TRANSITION_END: 'bsTransitionEnd',\n\n getUID(prefix) {\n do {\n // eslint-disable-next-line no-bitwise\n prefix += ~~(Math.random() * MAX_UID) // \"~~\" acts like a faster Math.floor() here\n } while (document.getElementById(prefix))\n return prefix\n },\n\n getSelectorFromElement(element) {\n let selector = element.getAttribute('data-target')\n if (!selector || selector === '#') {\n selector = element.getAttribute('href') || ''\n }\n\n try {\n const $selector = $(document).find(selector)\n return $selector.length > 0 ? selector : null\n } catch (error) {\n return null\n }\n },\n\n reflow(element) {\n return element.offsetHeight\n },\n\n triggerTransitionEnd(element) {\n $(element).trigger(transition.end)\n },\n\n supportsTransitionEnd() {\n return Boolean(transition)\n },\n\n isElement(obj) {\n return (obj[0] || obj).nodeType\n },\n\n typeCheckConfig(componentName, config, configTypes) {\n for (const property in configTypes) {\n if (Object.prototype.hasOwnProperty.call(configTypes, property)) {\n const expectedTypes = configTypes[property]\n const value = config[property]\n const valueType = value && Util.isElement(value) ?\n 'element' : toType(value)\n\n if (!new RegExp(expectedTypes).test(valueType)) {\n throw new Error(\n `${componentName.toUpperCase()}: ` +\n `Option \"${property}\" provided type \"${valueType}\" ` +\n `but expected type \"${expectedTypes}\".`)\n }\n }\n }\n }\n }\n\n setTransitionEndSupport()\n\n return Util\n\n})($)\n\nexport default Util\n","import $ from 'jquery'\nimport Util from './util'\n\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap (v4.0.0-beta.2): alert.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * ----------------------------------------Line truncated
+7
View File
@@ -0,0 +1,7 @@
/*!
* Bootstrap v4.0.0-beta.2 (https://getbootstrap.com)
* Copyright 2011-2017 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
*/
var bootstrap=function(t,e,n){"use strict";function i(t,e){for(var n=0;n<e.length;n++){var i=e[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(t,i.key,i)}}e=e&&e.hasOwnProperty("default")?e.default:e,n=n&&n.hasOwnProperty("default")?n.default:n;var s=function(){function t(t){return{}.toString.call(t).match(/\s([a-zA-Z]+)/)[1].toLowerCase()}function n(){return{bindType:r.end,delegateType:r.end,handle:function(t){if(e(t.target).is(this))return t.handleObj.handler.apply(this,arguments)}}}function i(){if(window.QUnit)return!1;var t=document.createElement("bootstrap");for(var e in o)if("undefined"!=typeof t.style[e])return{end:o[e]};return!1}function s(t){var n=this,i=!1;return e(this).one(a.TRANSITION_END,function(){i=!0}),setTimeout(function(){i||a.triggerTransitionEnd(n)},t),this}var r=!1,o={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"},a={TRANSITION_END:"bsTransitionEnd",getUID:function(t){do{t+=~~(1e6*Math.random())}while(document.getElementById(t));return t},getSelectorFromElement:function(t){var n=t.getAttribute("data-target");n&&"#"!==n||(n=t.getAttribute("href")||"");try{return e(document).find(n).length>0?n:null}catch(t){return null}},reflow:function(t){return t.offsetHeight},triggerTransitionEnd:function(t){e(t).trigger(r.end)},supportsTransitionEnd:function(){return Boolean(r)},isElement:function(t){return(t[0]||t).nodeType},typeCheckConfig:function(e,n,i){for(var s in i)if(Object.prototype.hasOwnProperty.call(i,s)){var r=i[s],o=n[s],l=o&&a.isElement(o)?"element":t(o);if(!new RegExp(r).test(l))throw new Error(e.toUpperCase()+': Option "'+s+'" provided type "'+l+'" but expected type "'+r+'".')}}};return r=i(),e.fn.emulateTransitionEnd=s,a.supportsTransitionEnd()&&(e.event.special[a.TRANSITION_END]=n()),a}(),r=function(t,e,n){return e&&i(t.prototype,e),n&&i(t,n),t},o=function(t,e){t.prototype=Object.create(e.prototype),t.prototype.constructor=t,t.__proto__=e},a=function(){var t="alert",n=e.fn[t],i={CLOSE:"close.bs.alert",CLOSED:"closed.bs.alert",CLICK_DATA_API:"click.bs.alert.data-api"},o={ALERT:"alert",FADE:"fade",SHOW:"show"},a=function(){function t(t){this._element=t}var n=t.prototype;return n.close=function(t){t=t||this._element;var e=this._getRootElement(t);this._triggerCloseEvent(e).isDefaultPrevented()||this._removeElement(e)},n.dispose=function(){e.removeData(this._element,"bs.alert"),this._element=null},n._getRootElement=function(t){var n=s.getSelectorFromElement(t),i=!1;return n&&(i=e(n)[0]),i||(i=e(t).closest("."+o.ALERT)[0]),i},n._triggerCloseEvent=function(t){var n=e.Event(i.CLOSE);return e(t).trigger(n),n},n._removeElement=function(t){var n=this;e(t).removeClass(o.SHOW),s.supportsTransitionEnd()&&e(t).hasClass(o.FADE)?e(t).one(s.TRANSITION_END,function(e){return n._destroyElement(t,e)}).emulateTransitionEnd(150):this._destroyElement(t)},n._destroyElement=function(t){e(t).detach().trigger(i.CLOSED).remove()},t._jQueryInterface=function(n){return this.each(function(){var i=e(this),s=i.data("bs.alert");s||(s=new t(this),i.data("bs.alert",s)),"close"===n&&s[n](this)})},t._handleDismiss=function(t){return function(e){e&&e.preventDefault(),t.close(this)}},r(t,null,[{key:"VERSION",get:function(){return"4.0.0-beta.2"}}]),t}();return e(document).on(i.CLICK_DATA_API,{DISMISS:'[data-dismiss="alert"]'}.DISMISS,a._handleDismiss(new a)),e.fn[t]=a._jQueryInterface,e.fn[t].Constructor=a,e.fn[t].noConflict=function(){return e.fn[t]=n,a._jQueryInterface},a}(),l=function(){var t="button",n=e.fn[t],i={ACTIVE:"active",BUTTON:"btn",FOCUS:"focus"},s={DATA_TOGGLE_CARROT:'[data-toggle^="button"]',DATA_TOGGLE:'[data-toggle="buttons"]',INPUT:"input",ACTIVE:".active",BUTTON:".btn"},o={CLICK_DATA_API:"click.bs.button.data-api",FOCUS_BLUR_DATA_API:"focus.bs.button.data-api blur.bs.button.data-api"},a=function(){function t(t){this._element=t}var n=t.prototype;return n.toggle=function(){var t=!0,n=!0,r=e(this._element).closest(s.DATA_TOGGLE)[0];if(r){var o=e(this._element).find(s.INPUT)[0];if(o){if("radio"===o.type)if(o.checked&&e(this._element).hasClass(i.ACTIVE))t=!1;else{var a=e(r).find(s.ACTIVE)[0];a&&e(a).removeClass(i.ACTIVE)}if(t){if(o.hasAttribute("disabled")||r.hasAttribute("disabled")||o.classList.contains("disabled")||r.classList.contains("disabled"))return;o.checked=!e(this._element).hasClass(i.ACTIVE),e(o).trigger("change")}o.focus(),n=!1}}n&&this._element.setAttribute("aria-pressed",!e(this._element).hasClass(i.ACTIVE)),t&&e(this._element).toggleClass(i.ACTIVE)},n.dispose=function(){e.removeData(this._element,"bs.button"),this._element=null},t._jQueryInterface=function(n){return this.each(function(){var i=e(this).data("bs.button");i||(i=new t(this),e(this).data("bs.button",i)),"toggle"===n&&i[n]()})},r(t,null,[{key:"VERSION",get:function(){return"4.0.0-beta.2"}}]),t}();return e(document).on(o.CLICK_DATA_API,s.DATA_TOGGLE_CARROT,function(t){t.preventDefault();Line truncated
//# sourceMappingURL=bootstrap.min.js.map
@@ -0,0 +1 @@
{"version":3,"sources":["../../js/src/util.js","../../js/src/alert.js","../../js/src/button.js","../../js/src/carousel.js","../../js/src/collapse.js","../../js/src/dropdown.js","../../js/src/modal.js","../../js/src/tooltip.js","../../js/src/popover.js","../../js/src/scrollspy.js","../../js/src/tab.js","../../js/src/index.js"],"names":["Util","toType","obj","toString","call","match","toLowerCase","getSpecialTransitionEndEvent","transition","end","event","$","target","is","this","handleObj","handler","apply","arguments","transitionEndTest","window","QUnit","el","document","createElement","name","TransitionEndEvent","style","transitionEndEmulator","duration","called","one","TRANSITION_END","triggerTransitionEnd","_this","prefix","Math","random","getElementById","element","selector","getAttribute","find","length","error","offsetHeight","trigger","Boolean","nodeType","componentName","config","configTypes","property","Object","prototype","hasOwnProperty","expectedTypes","value","valueType","isElement","RegExp","test","Error","toUpperCase","fn","emulateTransitionEnd","supportsTransitionEnd","special","Alert","NAME","JQUERY_NO_CONFLICT","Event","ClassName","_element","close","rootElement","_getRootElement","_triggerCloseEvent","isDefaultPrevented","_removeElement","dispose","removeData","getSelectorFromElement","parent","closest","ALERT","closeEvent","CLOSE","removeClass","SHOW","hasClass","FADE","_destroyElement","detach","CLOSED","remove","_jQueryInterface","each","$element","data","_handleDismiss","alertInstance","preventDefault","on","CLICK_DATA_API","DISMISS","Constructor","noConflict","Button","Selector","toggle","triggerChangeEvent","addAriaPressed","DATA_TOGGLE","input","INPUT","type","checked","ACTIVE","activeElement","hasAttribute","classList","contains","focus","setAttribute","toggleClass","DATA_TOGGLE_CARROT","button","BUTTON","FOCUS_BLUR_DATA_API","FOCUS","Carousel","DATA_KEY","EVENT_KEY","Default","DefaultType","Direction","_items","_interval","_activeElement","_isPaused","_isSliding","touchTimeout","_config","_getConfig","_indicatorsElement","INDICATORS","_addEventListeners","next","_slide","NEXT","nextWhenVisible","hidden","css","prev","PREV","pause","NEXT_PREV","cycle","interval","setInterval","visibilityState","bind","to","index","ACTIVE_ITEM","activeIndex","_getItemIndex","SLID","direction","off","extend","typeCheckConfig","keyboard","KEYDOWN","_this2","_keydown","MOUSEENTER","MOUSELEAVE","documentElement","TOUCHEND","setTimeout","tagName","which","makeArray","ITEM","indexOf","_getItemByDirection","isNextDirection","isPrevDirection","lastItemIndex","wrap","itemIndex","_triggerSlideEvent","relatedTarget","eventDirectionName","targetIndex","fromIndex","slideEvent","SLIDE","_setActiveIndicatorElement","nextIndicator","children","addClass","directionalClassName","orderClassName","activeElementIndex","nextElement","nextElementIndex","isCycling","LEFT","RIGHT","slidEvent","reflow","_this3","action","slide","_dataApiClickHandler","CAROUSEL","slideIndex","DATA_SLIDE","LOAD_DATA_API","DATA_RIDE","$carousel","Collapse","Dimension","_isTransitioning","_triggerArray","id","tabToggles","i","elem","filter","push","_parent","_getParent","_addAriaAndCollapsedClass","hide","show","actives","activesData","ACTIVES","startEvent","dimension","_getDimension","COLLAPSE","COLLAPSING","COLLAPSED","attr","setTransitioning","complete","SHOWN","scrollSize","slice","HIDE","getBoundingClientRect","HIDDEN","isTransitioning","WIDTH","HEIGHT","jquery","_getTargetFromElement","triggerArray","isOpen","$this","currentTarget","$trigger","$target","Dropdown","Popper","REGEXP_KEYDOWN","ARROW_UP_KEYCODE","AttachmentMap","_popper","_menu","_getMenuElement","_inNavbar","_detectNavbar","disabled","DISABLED","_getParentFromElement","isActive","_clearMenus","showEvent","DROPUP","MENULEFT","MENURIGHT","_getPopperConfig","NAVBAR_NAV","noop","destroy","update","scheduleUpdate","CLICK","stopPropagation","constructor","MENU","_getPlacement","$parentDropdown","placement","BOTTOM","TOP","TOPEND","BOTTOMEND","offsetConf","offset","offsets","popperConfig","flip","modifiers","applyStyle","toggles","context","dropdownMenu","hideEvent","parentNode","_dataApiKeydownHandler","items","VISIBLE_ITEMS","get","KEYDOWN_DATA_API","KEYUP_DATA_API","FORM_CHILD","e","Modal","_dialog","DIALOG","_backdrop","_isShown","_isBodyOverflowing","_ignoreBackdropClick","_originalBodyPadding","_scrollbarWidth","_checkScrollbar","_setScrollbar","_adjustDialog","body","OPEN","_setEscapeEvent","_setResizeEvent","CLICK_DISMISS","DATA_DISMISS","MOUSEDOWN_DISMISS","MOUSEUP_DISMISS","_showBackdrop","_showElement","FOCUSIN","_hideModal","handleUpdate","Node","ELEMENT_NODE","appendChild","display","removeAttribute","scrollTop","_enforceFocus","shownEvent","transitionComplete","_this4","has","KEYDOWN_DISMISS","RESIZE","_this6","_resetAdjustments","_resetScrollbar","_this7","_removeBackdrop","callback","animate","backdrop","doAnimate","className","BACKDROP","appendTo","_this8","callbacLine truncated
+231
View File
@@ -0,0 +1,231 @@
@import url('http://fonts.googleapis.com/css?family=Kalam');
body {
background-color: black;
font-family: 'ChicagoFLFRegular';
font-weight: normal;
font-style: normal;
font-size: 90%;
color: white;
height: 100%;
}
header {
height: 200px;
position: relative;
}
section {
position: relative;
}
#sectionhash {
height: 20px;
}
#sectionwees {
height: 340px;
}
#sectionanswer {
height: 150px;
}
#sectionform {
height: 400px;
}
footer {
height: 200px;
position: relative;
}
td {
vertical-align: top;
padding-right:10px;
padding-bottom: 10px;
}
form table {
width: 100%;
border-collapse: collapse;
}
input {
width: 100%;
outline-color: #b4363b;
}
input.levelradio {
width: 10%;
}
#hashtags {
font-size: x-small;
max-width:400px;
width: 100%;
overflow: auto;
margin: auto;
position: absolute;
top: 0; left: 0; bottom: 0; right: 0;
text-align: center;
}
.headline {
padding-bottom: 4px;
}
#header {
width: 50%;
overflow: auto;
margin: auto;
position: absolute;
left: 0; bottom: 0; right: 0;
text-align: center;
display: table-cell;
vertical-align: middle;
}
#headerimg {
max-width:400px;
width: 100%;
}
#wees {
max-width:400px;
width: 100%;
overflow: auto;
margin: auto;
position: absolute;
top: 0; left: 0; bottom: 0; right: 0;
text-align: left;
}
#answer {
max-width:400px;
width: 100%;
overflow: auto;
margin: auto;
position: absolute;
top: 0; left: 0; bottom: 0; right: 0;
text-align: left;
}
#applyform {
max-width:400px;
width: 100%;
overflow: auto;
margin: auto;
position: absolute;
top: 0; left: 0; bottom: 0; right: 0;
text-align: left;
}
#apply {
background-color: #b4363b;
border: medium solid #b4363b;
font-family: 'ChicagoFLFRegular';
font-weight: normal;
font-style: normal;
color: white;
font-size: medium;
margin-top: 20px;
}
#footer {
max-width:400px;
width: 100%;
overflow: auto;
margin: auto;
position: absolute;
top: 0; left: 0; bottom: 0; right: 0;
text-align: left;
}
#planetdiv {
position: fixed;
padding: 10px;
bottom: 0;
left: 0;
right: 0;
height: 330px;
overflow: hidden;
z-index: -1;
}
#planetcut {
width: 100%;
height: auto;
max-height: 320px;
overflow: auto;
margin: auto;
position: absolute;
left: 0; bottom: 0; right: 0;
text-align: center;
display: table-cell;
vertical-align: middle;
z-index: -2;
}
#kurzlogo {
width: 150px;
overflow: auto;
margin: auto;
position: absolute;
left: 30px; bottom: 10px;
text-align: center;
display: table-cell;
vertical-align: middle;
z-index: -1;
}
#thlogo {
width: 210px;
overflow: auto;
margin: auto;
position: absolute;
left: 210px; bottom: 10px;
text-align: center;
display: table-cell;
vertical-align: middle;
z-index: -1;
}
#skydiv {
position: fixed;
padding: 10px;
top: 0;
left: 0;
right: 0;
height: 600px;
overflow: hidden;
z-index: -1;
}
#skyl{
overflow: auto;
margin: auto;
position: absolute;
top: 0; left: 0; bottom: 0;
}
#skyr {
overflow: auto;
margin: auto;
position: absolute;
top: 0; right: 0; bottom: 0;
}
a {
color: white;
text-decoration: none;
font-weight: bold;
}
+1
View File
@@ -0,0 +1 @@
@-webkit-keyframes passing-through{0%{opacity:0;-webkit-transform:translateY(40px);-moz-transform:translateY(40px);-ms-transform:translateY(40px);-o-transform:translateY(40px);transform:translateY(40px)}30%, 70%{opacity:1;-webkit-transform:translateY(0px);-moz-transform:translateY(0px);-ms-transform:translateY(0px);-o-transform:translateY(0px);transform:translateY(0px)}100%{opacity:0;-webkit-transform:translateY(-40px);-moz-transform:translateY(-40px);-ms-transform:translateY(-40px);-o-transform:translateY(-40px);transform:translateY(-40px)}}@-moz-keyframes passing-through{0%{opacity:0;-webkit-transform:translateY(40px);-moz-transform:translateY(40px);-ms-transform:translateY(40px);-o-transform:translateY(40px);transform:translateY(40px)}30%, 70%{opacity:1;-webkit-transform:translateY(0px);-moz-transform:translateY(0px);-ms-transform:translateY(0px);-o-transform:translateY(0px);transform:translateY(0px)}100%{opacity:0;-webkit-transform:translateY(-40px);-moz-transform:translateY(-40px);-ms-transform:translateY(-40px);-o-transform:translateY(-40px);transform:translateY(-40px)}}@keyframes passing-through{0%{opacity:0;-webkit-transform:translateY(40px);-moz-transform:translateY(40px);-ms-transform:translateY(40px);-o-transform:translateY(40px);transform:translateY(40px)}30%, 70%{opacity:1;-webkit-transform:translateY(0px);-moz-transform:translateY(0px);-ms-transform:translateY(0px);-o-transform:translateY(0px);transform:translateY(0px)}100%{opacity:0;-webkit-transform:translateY(-40px);-moz-transform:translateY(-40px);-ms-transform:translateY(-40px);-o-transform:translateY(-40px);transform:translateY(-40px)}}@-webkit-keyframes slide-in{0%{opacity:0;-webkit-transform:translateY(40px);-moz-transform:translateY(40px);-ms-transform:translateY(40px);-o-transform:translateY(40px);transform:translateY(40px)}30%{opacity:1;-webkit-transform:translateY(0px);-moz-transform:translateY(0px);-ms-transform:translateY(0px);-o-transform:translateY(0px);transform:translateY(0px)}}@-moz-keyframes slide-in{0%{opacity:0;-webkit-transform:translateY(40px);-moz-transform:translateY(40px);-ms-transform:translateY(40px);-o-transform:translateY(40px);transform:translateY(40px)}30%{opacity:1;-webkit-transform:translateY(0px);-moz-transform:translateY(0px);-ms-transform:translateY(0px);-o-transform:translateY(0px);transform:translateY(0px)}}@keyframes slide-in{0%{opacity:0;-webkit-transform:translateY(40px);-moz-transform:translateY(40px);-ms-transform:translateY(40px);-o-transform:translateY(40px);transform:translateY(40px)}30%{opacity:1;-webkit-transform:translateY(0px);-moz-transform:translateY(0px);-ms-transform:translateY(0px);-o-transform:translateY(0px);transform:translateY(0px)}}@-webkit-keyframes pulse{0%{-webkit-transform:scale(1);-moz-transform:scale(1);-ms-transform:scale(1);-o-transform:scale(1);transform:scale(1)}10%{-webkit-transform:scale(1.1);-moz-transform:scale(1.1);-ms-transform:scale(1.1);-o-transform:scale(1.1);transform:scale(1.1)}20%{-webkit-transform:scale(1);-moz-transform:scale(1);-ms-transform:scale(1);-o-transform:scale(1);transform:scale(1)}}@-moz-keyframes pulse{0%{-webkit-transform:scale(1);-moz-transform:scale(1);-ms-transform:scale(1);-o-transform:scale(1);transform:scale(1)}10%{-webkit-transform:scale(1.1);-moz-transform:scale(1.1);-ms-transform:scale(1.1);-o-transform:scale(1.1);transform:scale(1.1)}20%{-webkit-transform:scale(1);-moz-transform:scale(1);-ms-transform:scale(1);-o-transform:scale(1);transform:scale(1)}}@keyframes pulse{0%{-webkit-transform:scale(1);-moz-transform:scale(1);-ms-transform:scale(1);-o-transform:scale(1);transform:scale(1)}10%{-webkit-transform:scale(1.1);-moz-transform:scale(1.1);-ms-transform:scale(1.1);-o-transform:scale(1.1);transform:scale(1.1)}20%{-webkit-transform:scale(1);-moz-transform:scale(1);-ms-transform:scale(1);-o-transform:scale(1);transform:scale(1)}}.dropzone,.dropzone *{box-sizing:border-box}.dropzone{min-height:150px;border:2px solid rgba(0,0,0,0.3);background:white;padding:20px 20px}.dropzone.dz-clickable{cursor:pointer}.dropzone.dz-clickable *{cursor:default}.dropzone.dz-clickable .dz-message,.dropzone.dz-clickable .dz-message *{cursor:pointer}.dropzone.dz-started .dz-message{display:none}.dropzone.dz-drag-hover{border-style:solid}.dropzone.dz-drag-hover .dz-message{opacity:0.5}.dropzone .dz-message{text-align:center;margin:2em 0}.dropzone .dz-message .dz-button{background:none;color:inherit;border:none;padding:0;font:inherit;cursor:pointer;outline:inherit}.dropzone .dz-preview{position:relative;display:inline-block;vertical-align:top;margin:16px;min-height:100px}.dropzone .dz-preview:hover{z-index:1000}.dropzone .dz-preview:hover .dz-details{opacity:1}.dropzone .dz-preview.dz-file-preview .dz-image{border-radius:20px;background:#999;background:linear-gradient(to bottom, #eee, #ddd)}.dropzone .dz-preview.dz-file-preview .dz-details{opacity:1}.dropzone .dz-preview.dz-image-preview{background:white}.dropzone .dz-preview.dz-image-preview .dz-details{-webkiLine truncated
+58
View File
@@ -0,0 +1,58 @@
#navbar-efi {
background-color: #ffe240;
margin-bottom: 20px;
}
/* Login Dropdown */
#login-dp{
min-width: 250px;
padding: 14px 14px 0;
overflow:hidden;
background-color:rgba(255,255,255,.8);
}
#login-dp .bottom{
background-color:rgba(255,255,255,.8);
border-top:1px solid #ddd;
clear:both;
padding:14px;
}
#login-dp .form-group {
margin-bottom: 10px;
}
#login-button {
text-align: right;
min-width: 250px;
}
#login-button:focus {
border-color: rgba(0, 0, 0, 0.8);
box-shadow: 0 10px 10px rgba(0, 0, 0, 0.075) inset, 0 0 8px rgba(126, 239, 104, 0.6);
outline: 0 none;
}
.icon {
width: 16px;
height: 16px;
}
.iconic-warning {
fill: #ffe240;
}
.svg-hidden {
display: none;
}
@media(max-width:768px){
#login-dp{
background-color: inherit;
color: #fff;
}
#login-dp .bottom{
background-color: inherit;
border-top:0 none;
}
}
+3
View File
@@ -0,0 +1,3 @@
.table-nostriped tbody tr:nth-of-type(odd) {
background-color:transparent;
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

+23
View File
@@ -0,0 +1,23 @@
.bfd-dropfield {
display: inline;
padding: 5px; }
.bfd-dropfield-inner {
border: 5px dashed #888;
color: #888;
cursor: pointer;
font-size: 32px;
text-align: center; }
.bfd-dropfield-inner:hover, .bfd-dropfield-inner.bfd-dragover {
border-color: #bbb;
color: #bbb; }
.bfd-info {
overflow: hidden;
white-space: nowrap; }
.bfd-error-message {
text-align: center; }
.bfd-remove {
cursor: pointer; }
+1
View File
@@ -0,0 +1 @@
!function(e){"use strict";e.FileDialog=function(a){var o=e.extend(e.FileDialog.defaults,a),t=e(["<div class='modal fade'>"," <div class='modal-dialog'>"," <div class='modal-content'>"," <div class='modal-header'>"," <button type='button' class='close' data-dismiss='modal'>"," <span aria-hidden='true'>&times;</span>"," <span class='sr-only'>",o.cancel_button," </span>"," </button>"," <h4 class='modal-title'>",o.title," </h4>"," </div>"," <div class='modal-body'>"," <input type='file' />"," <div class='bfd-dropfield'>"," <div class='bfd-dropfield-inner'>",o.drag_message," </div>"," </div>"," <div class='container-fluid bfd-files'>"," </div>"," </div>"," <div class='modal-footer'>"," <button type='button' class='btn btn-primary bfd-ok'>",o.ok_button," </button>"," <button type='button' class='btn btn-default bfd-cancel'"," data-dismiss='modal'>",o.cancel_button," </button>"," </div>"," </div>"," </div>","</div>"].join("")),n=!1,r=e("input:file",t),i=e(".bfd-dropfield",t),s=e(".bfd-dropfield-inner",i);s.css({height:o.dropheight,"padding-top":o.dropheight/2-32}),r.attr({accept:o.accept,multiple:o.multiple}),i.on("click.bfd",function(){r.trigger("click")});var d=[],l=[],c=function(a){var n,r,i=new FileReader;l.push(i),i.onloadstart=function(){},i.onerror=function(e){e.target.error.code!==e.target.error.ABORT_ERR&&n.parent().html(["<div class='bg-danger bfd-error-message'>",o.error_message,"</div>"].join("\n"))},i.onprogress=function(a){var o=Math.round(100*a.loaded/a.total)+"%";n.attr("aria-valuenow",a.loaded),n.css("width",o),e(".sr-only",n).text(o)},i.onload=function(e){a.content=e.target.result,d.push(a),n.removeClass("active")};var s=e(["<div class='col-xs-7 col-sm-4 bfd-info'>"," <span class='glyphicon glyphicon-remove bfd-remove'></span>&nbsp;"," <span class='glyphicon glyphicon-file'></span>&nbsp;"+a.name,"</div>","<div class='col-xs-5 col-sm-8 bfd-progress'>"," <div class='progress'>"," <div class='progress-bar progress-bar-striped active' role='progressbar'"," aria-valuenow='0' aria-valuemin='0' aria-valuemax='"+a.size+"'>"," <span class='sr-only'>0%</span>"," </div>"," </div>","</div>"].join(""));n=e(".progress-bar",s),e(".bfd-remove",s).tooltip({container:"body",html:!0,placement:"top",title:o.remove_message}).on("click.bfd",function(){var e=d.indexOf(a);e>=0&&d.pop(e),r.fadeOut();try{i.abort()}catch(o){}}),r=e("<div class='row'></div>"),r.append(s),e(".bfd-files",t).append(r),i["readAs"+o.readAs](a)},f=function(e){Array.prototype.forEach.apply(e,[c])};return r.change(function(e){e=e.originalEvent;var a=e.target.files;f(a);var o=r.clone(!0);r.replaceWith(o),r=o}),i.on("dragenter.bfd",function(){s.addClass("bfd-dragover")}).on("dragover.bfd",function(e){e=e.originalEvent,e.stopPropagation(),e.preventDefault(),e.dataTransfer.dropEffect="copy"}).on("dragleave.bfd drop.bfd",function(){s.removeClass("bfd-dragover")}).on("drop.bfd",function(e){e=e.originalEvent,e.stopPropagation(),e.preventDefault();var a=e.dataTransfer.files;0===a.length,f(a)}),e(".bfd-ok",t).on("click.bfd",function(){var a=e.Event("files.bs.filedialog");a.files=d,t.trigger(a),n=!0,t.modal("hide")}),t.on("hidden.bs.modal",function(){if(l.forEach(function(e){try{e.abort()}catch(a){}}),!n){var a=e.Event("cancel.bs.filedialog");t.trigger(a)}t.remove()}),e(document.body).append(t),t.modal(),t},e.FileDialog.defaults={accept:"*",cancel_button:"Close",drag_message:"Drop files here",dropheight:400,error_message:"An error occured while loading file",multiple:!0,ok_button:"OK",readAs:"DataURL",remove_message:"Remove&nbsp;file",title:"Load file(s)"}}(jQuery);
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

+1
View File
@@ -0,0 +1 @@
"use strict";function _typeof(e){return(_typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function _possibleConstructorReturn(e,t){return!t||"object"!==_typeof(t)&&"function"!=typeof t?_assertThisInitialized(e):t}function _getPrototypeOf(e){return(_getPrototypeOf=Object.setPrototypeOf?Object.getPrototypeOf:function(e){return e.__proto__||Object.getPrototypeOf(e)})(e)}function _assertThisInitialized(e){if(void 0===e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return e}function _inherits(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function");e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,writable:!0,configurable:!0}}),t&&_setPrototypeOf(e,t)}function _setPrototypeOf(e,t){return(_setPrototypeOf=Object.setPrototypeOf||function(e,t){return e.__proto__=t,e})(e,t)}function _classCallCheck(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function _defineProperties(e,t){for(var n=0;n<t.length;n++){var i=t[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(e,i.key,i)}}function _createClass(e,t,n){return t&&_defineProperties(e.prototype,t),n&&_defineProperties(e,n),e}var Emitter=function(){function e(){_classCallCheck(this,e)}return _createClass(e,[{key:"on",value:function(e,t){return this._callbacks=this._callbacks||{},this._callbacks[e]||(this._callbacks[e]=[]),this._callbacks[e].push(t),this}},{key:"emit",value:function(e){this._callbacks=this._callbacks||{};var t=this._callbacks[e];if(t){for(var n=arguments.length,i=new Array(1<n?n-1:0),r=1;r<n;r++)i[r-1]=arguments[r];var o=!0,a=!1,l=void 0;try{for(var s,u=t[Symbol.iterator]();!(o=(s=u.next()).done);o=!0){s.value.apply(this,i)}}catch(e){a=!0,l=e}finally{try{o||null==u.return||u.return()}finally{if(a)throw l}}}return this}},{key:"off",value:function(e,t){if(!this._callbacks||0===arguments.length)return this._callbacks={},this;var n=this._callbacks[e];if(!n)return this;if(1===arguments.length)return delete this._callbacks[e],this;for(var i=0;i<n.length;i++){if(n[i]===t){n.splice(i,1);break}}return this}}]),e}(),Dropzone=function(){function C(e,t){var n,i,r;if(_classCallCheck(this,C),(n=_possibleConstructorReturn(this,_getPrototypeOf(C).call(this))).element=e,n.version=C.version,n.defaultOptions.previewTemplate=n.defaultOptions.previewTemplate.replace(/\n*/g,""),n.clickableElements=[],n.listeners=[],n.files=[],"string"==typeof n.element&&(n.element=document.querySelector(n.element)),!n.element||null==n.element.nodeType)throw new Error("Invalid dropzone element.");if(n.element.dropzone)throw new Error("Dropzone already attached.");C.instances.push(_assertThisInitialized(n)),n.element.dropzone=_assertThisInitialized(n);var o=null!=(r=C.optionsForElement(n.element))?r:{};if(n.options=C.extend({},n.defaultOptions,o,null!=t?t:{}),n.options.forceFallback||!C.isBrowserSupported())return _possibleConstructorReturn(n,n.options.fallback.call(_assertThisInitialized(n)));if(null==n.options.url&&(n.options.url=n.element.getAttribute("action")),!n.options.url)throw new Error("No URL provided.");if(n.options.acceptedFiles&&n.options.acceptedMimeTypes)throw new Error("You can't provide both 'acceptedFiles' and 'acceptedMimeTypes'. 'acceptedMimeTypes' is deprecated.");if(n.options.uploadMultiple&&n.options.chunking)throw new Error("You cannot set both: uploadMultiple and chunking.");return n.options.acceptedMimeTypes&&(n.options.acceptedFiles=n.options.acceptedMimeTypes,delete n.options.acceptedMimeTypes),null!=n.options.renameFilename&&(n.options.renameFile=function(e){return n.options.renameFilename.call(_assertThisInitialized(n),e.name,e)}),n.options.method=n.options.method.toUpperCase(),(i=n.getExistingFallback())&&i.parentNode&&i.parentNode.removeChild(i),!1!==n.options.previewsContainer&&(n.options.previewsContainer?n.previewsContainer=C.getElement(n.options.previewsContainer,"previewsContainer"):n.previewsContainer=n.element),n.options.clickable&&(!0===n.options.clickable?n.clickableElements=[n.element]:n.clickableElements=C.getElements(n.options.clickable,"clickable")),n.init(),n}return _inherits(C,Emitter),_createClass(C,null,[{key:"initClass",value:function(){this.prototype.Emitter=Emitter,this.prototype.events=["drop","dragstart","dragend","dragenter","dragover","dragleave","addedfile","addedfiles","removedfile","thumbnail","error","errormultiple","processing","processingmultiple","uploadprogress","totaluploadprogress","sending","sendingmultiple","success","successmultiple","canceled","canceledmultiple","complete","completemultiple","reset","maxfilesexceeded","maxfilesreached","queuecomplete"],this.prototype.defaultOptions={url:null,method:"post",withCredentials:!1,timeout:3e4,parallelUploads:2,uploadMultiple:!1,cLine truncated
+2
View File
@@ -0,0 +1,2 @@
/*! jQuery v3.5.1 | (c) JS Foundation and other contributors | jquery.org/license */
!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],r=Object.getPrototypeOf,s=t.slice,g=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType},x=function(e){return null!=e&&e===e.window},E=C.document,c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.5.1",S=function(e,t){return new S.fn.init(e,t)};function p(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0<t&&t-1 in e)}S.fn=S.prototype={jquery:f,constructor:S,length:0,toArray:function(){return s.call(this)},get:function(e){return null==e?s.call(this):e<0?this[e+this.length]:this[e]},pushStack:function(e){var t=S.merge(this.constructor(),e);return t.prevObject=this,t},each:function(e){return S.each(this,e)},map:function(n){return this.pushStack(S.map(this,function(e,t){return n.call(e,t,e)}))},slice:function(){return this.pushStack(s.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},even:function(){return this.pushStack(S.grep(this,function(e,t){return(t+1)%2}))},odd:function(){return this.pushStack(S.grep(this,function(e,t){return t%2}))},eq:function(e){var t=this.length,n=+e+(e<0?t:0);return this.pushStack(0<=n&&n<t?[this[n]]:[])},end:function(){return this.prevObject||this.constructor()},push:u,sort:t.sort,splice:t.splice},S.extend=S.fn.extend=function(){var e,t,n,r,i,o,a=arguments[0]||{},s=1,u=arguments.length,l=!1;for("boolean"==typeof a&&(l=a,a=arguments[s]||{},s++),"object"==typeof a||m(a)||(a={}),s===u&&(a=this,s--);s<u;s++)if(null!=(e=arguments[s]))for(t in e)r=e[t],"__proto__"!==t&&a!==r&&(l&&r&&(S.isPlainObject(r)||(i=Array.isArray(r)))?(n=a[t],o=i&&!Array.isArray(n)?[]:i||S.isPlainObject(n)?n:{},i=!1,a[t]=S.extend(l,o,r)):void 0!==r&&(a[t]=r));return a},S.extend({expando:"jQuery"+(f+Math.random()).replace(/\D/g,""),isReady:!0,error:function(e){throw new Error(e)},noop:function(){},isPlainObject:function(e){var t,n;return!(!e||"[object Object]"!==o.call(e))&&(!(t=r(e))||"function"==typeof(n=v.call(t,"constructor")&&t.constructor)&&a.call(n)===l)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},globalEval:function(e,t,n){b(e,{nonce:t&&t.nonce},n)},each:function(e,t){var n,r=0;if(p(e)){for(n=e.length;r<n;r++)if(!1===t.call(e[r],r,e[r]))break}else for(r in e)if(!1===t.call(e[r],r,e[r]))break;return e},makeArray:function(e,t){var n=t||[];return null!=e&&(p(Object(e))?S.merge(n,"string"==typeof e?[e]:e):u.call(n,e)),n},inArray:function(e,t,n){return null==t?-1:i.call(t,e,n)},merge:function(e,t){for(var n=+t.length,r=0,i=e.length;r<n;r++)e[i++]=t[r];return e.length=i,e},grep:function(e,t,n){for(var r=[],i=0,o=e.length,a=!n;i<o;i++)!t(e[i],i)!==a&&r.push(e[i]);return r},map:function(e,t,n){var r,i,o=0,a=[];if(p(e))for(r=e.length;o<r;o++)null!=(i=t(e[o],o,n))&&a.push(i);else for(o in e)null!=(i=t(e[o],o,n))&&a.push(i);return g(a)},guid:1,support:y}),"function"==typeof Symbol&&(S.fn[Symbol.iterator]=t[Symbol.iterator]),S.each("Boolean Number String Function Array Date RegExp Object Error Symbol".split(" "),function(e,t){n["[object "+t+"]"]=t.toLowerCase()});var d=function(n){var e,d,b,o,i,h,f,g,w,u,l,T,C,a,E,v,s,c,y,S="sizzle"+1*new Date,p=n.document,k=0,r=0,m=ue(),x=ue(),A=ue(),N=ue(),D=function(e,t){return e===t&&(l=!0),0},j={}.hasOwnProperty,t=[],q=t.pop,L=t.push,H=t.push,O=t.slice,P=function(e,t){for(var n=0,r=e.length;n<r;n++)if(e[n]===t)return n;return-1},R="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",M="[\\x20\\t\\r\\n\\f]",I="(?:\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\[^\\r\\n\\f]|[\\w-]|[^\0-\\x7f])+",W="\\["+M+"*("+I+")(?:"+M+"*([*^$|!~]?=)"+M+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+I+"))|)"+M+"*\\]",F=":("+I+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+W+")*)|.*)\\)|)",B=new RegExp(M+"+","g"),$=new RegExp("^"+M+"+|((?:^|[^\\\\])(?:\\\\.)*)"+M+"+$","g"),_=new RegExp("^"+M+"*,"+M+"*"),z=new RegExp("^"+M+"*([>+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp(F),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+F),CHILD:new RegExp("^:(only|first|last|nth|nth-lLine truncated
Loaded 100 of 370 files, more files were not shown because too many files have changed in this diff. Show more