Release - Upload
No files matched your search
@@ -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"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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"]}
|
||||
@@ -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),
|
||||
]
|
||||
@@ -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)
|
||||
@@ -0,0 +1,3 @@
|
||||
from django.contrib import admin
|
||||
|
||||
# Register your models here.
|
||||
@@ -0,0 +1,5 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class AuthStuffConfig(AppConfig):
|
||||
name = 'authstuff'
|
||||
@@ -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)),
|
||||
],
|
||||
),
|
||||
]
|
||||
@@ -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)
|
||||
@@ -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
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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)
|
||||
@@ -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()
|
||||
@@ -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}
|
||||
@@ -0,0 +1 @@
|
||||
loaddata medinf/fixtures/groups.json
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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	et*$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")
|
||||
@@ -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
|
||||
]
|
||||
@@ -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)
|
||||
@@ -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()
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
from django.contrib import admin
|
||||
|
||||
# Register your models here.
|
||||
@@ -0,0 +1,5 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class PruefplanParserConfig(AppConfig):
|
||||
name = 'pruefplan_parser'
|
||||
@@ -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
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -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": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -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
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -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')),
|
||||
],
|
||||
),
|
||||
]
|
||||
@@ -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)
|
||||
@@ -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'),
|
||||
]
|
||||
@@ -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)
|
||||
@@ -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})
|
||||
@@ -0,0 +1,4 @@
|
||||
#from django.contrib import admin
|
||||
#from .models import Lecturer
|
||||
|
||||
#admin.site.register(Lecturer)
|
||||
@@ -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),
|
||||
),
|
||||
]
|
||||
@@ -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
|
||||
@@ -0,0 +1,3 @@
|
||||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
||||
@@ -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'),
|
||||
]
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
.table-nostriped tbody tr:nth-of-type(odd) {
|
||||
background-color:transparent;
|
||||
}
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
@@ -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; }
|
||||
@@ -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'>×</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> "," <span class='glyphicon glyphicon-file'></span> "+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 file",title:"Load file(s)"}}(jQuery);
|
||||
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 35 KiB |
|
After Width: | Height: | Size: 9.3 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 11 KiB |
@@ -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
|
||||
@@ -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
|
||||