diff --git a/biscuit/core/dashboard/README.md b/biscuit/core/dashboard/README.md index b9a8f00b2082812dfb0eb882849d75574277e19e..5246b5c011be74320aa37e498abc2bc982168314 100644 --- a/biscuit/core/dashboard/README.md +++ b/biscuit/core/dashboard/README.md @@ -43,32 +43,3 @@ Als Benachrichtigung gilt eine Aktion, die den Nutzer betrifft. - [1] https://docs.djangoproject.com/en/2.1/ref/request-response/#django.http.HttpRequest.build_absolute_uri - [2] https://docs.djangoproject.com/en/2.1/ref/urlresolvers/#reverse -## Caches -### Sitecache -Ein Seitencache basiert auf dem Django-Decorator `@cache_page` und cacht die HTML-Ausgabe des entsprechenden Views. - -### Variablencache -Ein Variablencache nutzt die Low-Level-Cache-API von Django und speichert den Inhalt einer Variable. - -### Verwaltung -Jedes gecachte Objekt (ob Sitecache oder Variablencache) benötigt ein Cache-Objekt in der DB. Bei Cacheinhalten für die nur eine Variable gespeichert werden muss oder ein View, wird die Datei `caches.py` verwendet, wo der Cache als Konstante gespeichert ist: -``` -<EXAMPLE_CACHE>, _ = Cache.objects.get_or_create(id="<example_cache>", - defaults={ - "site_cache": <True/False>, - "name": "<Readable name>", - "expiration_time": <10>}) # in seconds - -``` -#### Variablencache -Für Variablencaches kann mit der Funktion `get()` eines Cache-Objektes der aktuelle Inhalt des Caches abgefragt werden. -Bei abgelaufenen Caches wird `False` zurückgeben, dann ist der Wert neu zu berechnen und mit `update(<new_value>)` zu aktualisieren, wobei die Aktualisierungszeit automatisch zurückgesetzt wird. - -#### Sitecache -Für einen Sitecache kann folgender Decorator zum entsprechenden View hinzugefügt werden: -``` -@cache_page(<EXAMPLE_CACHE>.expiration_time) -``` - -### Literatur -- https://docs.djangoproject.com/en/2.2/topics/cache/ diff --git a/biscuit/core/dashboard/caches.py b/biscuit/core/dashboard/caches.py deleted file mode 100644 index 663df3c5e5d474fb57c65775c9e0dc4ebe1025c3..0000000000000000000000000000000000000000 --- a/biscuit/core/dashboard/caches.py +++ /dev/null @@ -1,48 +0,0 @@ -from dashboard.models import Cache - -PARSED_LESSONS_CACHE, _ = Cache.objects.get_or_create(id="parsed_lessons", - defaults={"name": "Geparste Stunden (Regelplan)", - "expiration_time": 60 * 60 * 24}) - -DRIVE_CACHE, _ = Cache.objects.get_or_create(id="drive", - defaults={"name": "Zwischenspeicher für teachers, rooms, classses, etc.", - "expiration_time": 60}) - -EXPIRATION_TIME_CACHE_FOR_PLAN_CACHES, _ = Cache.objects.get_or_create(id="expiration_time_cache_for_plan_caches", - defaults={"name": "Ablaufzeit für Plan-Caches", - "expiration_time": 60}) - -BACKGROUND_CACHE_REFRESH, _ = Cache.objects.get_or_create(id="background_cache_refresh", - defaults={ - "name": "Hintergrundaktualisierung der Variablencaches", - "expiration_time": 0}) - -PLAN_VIEW_CACHE, _ = Cache.objects.get_or_create(id="plan_view_cache", - defaults={ - "site_cache": True, - "name": "Wochenplan (Regelplan/SMART PLAN)", - "expiration_time": 60}) - -MY_PLAN_VIEW_CACHE, _ = Cache.objects.get_or_create(id="my_plan_view_cache", - defaults={ - "site_cache": True, - "name": "Mein Plan", - "expiration_time": 60}) - -SUBS_VIEW_CACHE, _ = Cache.objects.get_or_create(id="subs_view_cache", - defaults={ - "site_cache": True, - "name": "Vertretungen (Tabellenansicht)", - "expiration_time": 60}) - -LATEST_ARTICLE_CACHE, _ = Cache.objects.get_or_create(id="latest_article_cache", - defaults={ - "name": "Letzter Artikel von der Homepage", - "expiration_time": 60 - }) - -CURRENT_EVENTS_CACHE, _ = Cache.objects.get_or_create(id="current_events_cache", - defaults={ - "name": "Aktuelle Termine", - "expiration_time": 60 - }) diff --git a/biscuit/core/dashboard/management/commands/refresh_caches.py b/biscuit/core/dashboard/management/commands/refresh_caches.py deleted file mode 100644 index 3ed4421d4d6f3c3cc29a16ad8876c63eedd7058d..0000000000000000000000000000000000000000 --- a/biscuit/core/dashboard/management/commands/refresh_caches.py +++ /dev/null @@ -1,83 +0,0 @@ -import datetime - -from django.core.management import BaseCommand -from django.utils import timezone - -from dashboard.caches import BACKGROUND_CACHE_REFRESH -from dashboard.models import Cache -from util.network import get_newest_article_from_news, get_current_events_with_cal -from timetable.views import get_next_weekday_with_time, get_calendar_week -from untisconnect.drive import build_drive, TYPE_TEACHER, TYPE_CLASS, TYPE_ROOM -from untisconnect.parse import parse -from untisconnect.plan import get_plan - - -class Command(BaseCommand): - help = 'Refresh all var caches' - - def start(self, s): - self.stdout.write(s) - - def finish(self): - self.stdout.write(self.style.SUCCESS(' Erledigt.')) - - def handle(self, *args, **options): - self.start("Alte Caches löschen ...") - for cache in Cache.objects.filter(needed_until__isnull=False): - if not cache.is_needed(): - print("Ist nicht mehr benötigt:", cache, ", benötigt bis", cache.needed_until) - cache.delete() - self.finish() - - self.start("Aktualisiere Drive ... ") - drive = build_drive(force_update=True) - print(drive) - self.finish() - - self.start("Aktualisiered Lessons ...") - parse(force_update=True) - self.finish() - - self.start("Aktualisiere Pläne ...") - - days = [] - days.append(get_next_weekday_with_time(timezone.now(), timezone.now().time())) - days.append(get_next_weekday_with_time(days[0] + datetime.timedelta(days=1), datetime.time(0))) - print(days) - - types = [ - (TYPE_TEACHER, "teachers"), - (TYPE_CLASS, "classes"), - (TYPE_ROOM, "rooms") - ] - for type_id, type_key in types: - self.start(type_key) - - for id, obj in drive[type_key].items(): - self.start(" " + obj.name if obj.name is not None else "") - self.start(" Regelplan") - get_plan(type_id, id, force_update=True) - for day in days: - - calendar_week = day.isocalendar()[1] - if day != days[0] and days[0].isocalendar()[1] == calendar_week and days[0].year == day.year: - continue - monday_of_week = get_calendar_week(calendar_week, day.year)["first_day"] - - self.start(" " + str(monday_of_week)) - get_plan(type_id, id, smart=True, monday_of_week=monday_of_week, force_update=True) - - self.finish() - - self.start("Aktualisiere Artikel ...") - get_newest_article_from_news(force_update=True) - self.finish() - - self.start("Aktualisiere Termine ...") - get_current_events_with_cal(force_update=True) - self.finish() - - self.start("Aktualisierungszeitpunkt in der Datenbank speichern ...") - BACKGROUND_CACHE_REFRESH.last_time_updated = timezone.now() - BACKGROUND_CACHE_REFRESH.save() - self.finish() diff --git a/biscuit/core/dashboard/migrations/0001_initial.py b/biscuit/core/dashboard/migrations/0001_initial.py deleted file mode 100644 index b98c580d6c71ce0871d5260d9ae591322e824b0e..0000000000000000000000000000000000000000 --- a/biscuit/core/dashboard/migrations/0001_initial.py +++ /dev/null @@ -1,42 +0,0 @@ -# Generated by Django 2.2.1 on 2019-05-29 15:06 - -from django.conf import settings -from django.db import migrations, models -import django.db.models.deletion -import django.utils.timezone - - -class Migration(migrations.Migration): - - initial = True - - dependencies = [ - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ] - - operations = [ - migrations.CreateModel( - name='Notification', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('title', models.CharField(max_length=200)), - ('description', models.TextField(max_length=500)), - ('link', models.URLField(blank=True)), - ('app', models.CharField(max_length=100)), - ('created_at', models.DateTimeField(default=django.utils.timezone.now)), - ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='notifications', - to=settings.AUTH_USER_MODEL)), - ], - ), - migrations.CreateModel( - name='Activity', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('title', models.CharField(max_length=200)), - ('description', models.TextField(max_length=500)), - ('app', models.CharField(max_length=100)), - ('created_at', models.DateTimeField(default=django.utils.timezone.now)), - ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), - ], - ), - ] diff --git a/biscuit/core/dashboard/migrations/0002_cache.py b/biscuit/core/dashboard/migrations/0002_cache.py deleted file mode 100644 index 1d146b35c7961c326f2b7de0bcf33ea6bdb552a5..0000000000000000000000000000000000000000 --- a/biscuit/core/dashboard/migrations/0002_cache.py +++ /dev/null @@ -1,25 +0,0 @@ -# Generated by Django 2.2.1 on 2019-08-25 10:51 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - dependencies = [ - ('dashboard', '0001_initial'), - ] - - operations = [ - migrations.CreateModel( - name='Cache', - fields=[ - ('id', - models.CharField(max_length=150, primary_key=True, serialize=False, unique=True, verbose_name='ID')), - ('name', models.CharField(max_length=150, verbose_name='Name')), - ('expiration_time', models.IntegerField(default=20, verbose_name='Ablaufzeit')), - ], - options={ - 'verbose_name': 'Cacheeintrag', - 'verbose_name_plural': 'Cacheeinträge', - }, - ), - ] diff --git a/biscuit/core/dashboard/migrations/0002_notification_read.py b/biscuit/core/dashboard/migrations/0002_notification_read.py deleted file mode 100644 index 19cc479866c684399fe5eb3c833a61e0c9e7aa98..0000000000000000000000000000000000000000 --- a/biscuit/core/dashboard/migrations/0002_notification_read.py +++ /dev/null @@ -1,17 +0,0 @@ -# Generated by Django 2.2.1 on 2019-09-01 08:40 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - dependencies = [ - ('dashboard', '0001_initial'), - ] - - operations = [ - migrations.AddField( - model_name='notification', - name='read', - field=models.BooleanField(default=False), - ), - ] diff --git a/biscuit/core/dashboard/migrations/0003_cache_last_time_updated.py b/biscuit/core/dashboard/migrations/0003_cache_last_time_updated.py deleted file mode 100644 index 2cda5789033367e5a6cac0ab4c87543b82e4a849..0000000000000000000000000000000000000000 --- a/biscuit/core/dashboard/migrations/0003_cache_last_time_updated.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 2.2.1 on 2019-08-25 11:21 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - dependencies = [ - ('dashboard', '0002_cache'), - ] - - operations = [ - migrations.AddField( - model_name='cache', - name='last_time_updated', - field=models.DateTimeField(blank=True, null=True, - verbose_name='Letzter Aktualisierungszeitpunkt des Caches'), - ), - ] diff --git a/biscuit/core/dashboard/migrations/0004_cache_site_cache.py b/biscuit/core/dashboard/migrations/0004_cache_site_cache.py deleted file mode 100644 index d5ed2edb969cd34a0b45c5195ae4014c5f2a38c8..0000000000000000000000000000000000000000 --- a/biscuit/core/dashboard/migrations/0004_cache_site_cache.py +++ /dev/null @@ -1,17 +0,0 @@ -# Generated by Django 2.2.1 on 2019-08-25 11:27 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - dependencies = [ - ('dashboard', '0003_cache_last_time_updated'), - ] - - operations = [ - migrations.AddField( - model_name='cache', - name='site_cache', - field=models.BooleanField(default=False, verbose_name='Seitencache?'), - ), - ] diff --git a/biscuit/core/dashboard/migrations/0005_cache_needed_until.py b/biscuit/core/dashboard/migrations/0005_cache_needed_until.py deleted file mode 100644 index e1669563cba91ee60e961d442af05897e68f12e9..0000000000000000000000000000000000000000 --- a/biscuit/core/dashboard/migrations/0005_cache_needed_until.py +++ /dev/null @@ -1,17 +0,0 @@ -# Generated by Django 2.2.6 on 2019-11-08 20:26 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - dependencies = [ - ('dashboard', '0004_cache_site_cache'), - ] - - operations = [ - migrations.AddField( - model_name='cache', - name='needed_until', - field=models.DateField(default=None, null=True, verbose_name='Benötigt bis'), - ), - ] diff --git a/biscuit/core/dashboard/migrations/0006_merge_20191118_1939.py b/biscuit/core/dashboard/migrations/0006_merge_20191118_1939.py deleted file mode 100644 index 057086014b0e26b629955e76c6cdea6a40428772..0000000000000000000000000000000000000000 --- a/biscuit/core/dashboard/migrations/0006_merge_20191118_1939.py +++ /dev/null @@ -1,13 +0,0 @@ -# Generated by Django 2.2.6 on 2019-11-18 18:39 - -from django.db import migrations - - -class Migration(migrations.Migration): - dependencies = [ - ('dashboard', '0005_cache_needed_until'), - ('dashboard', '0002_notification_read'), - ] - - operations = [ - ] diff --git a/biscuit/core/dashboard/models.py b/biscuit/core/dashboard/models.py index 8a26ce363f72ef0867614a389fc1c7b1062ee16f..5b1001042aeedb8874958a80dc8ca39583e7e333 100644 --- a/biscuit/core/dashboard/models.py +++ b/biscuit/core/dashboard/models.py @@ -46,82 +46,3 @@ def register_notification(user, title, description, app="SchoolApps", link=""): } send_mail_with_template(title, [user.email], "mail/notification.txt", "mail/notification.html", context) - -class Cache(models.Model): - id = models.CharField(max_length=150, unique=True, primary_key=True, verbose_name="ID") - name = models.CharField(max_length=150, verbose_name="Name") - expiration_time = models.IntegerField(default=20, verbose_name="Ablaufzeit") - last_time_updated = models.DateTimeField(blank=True, null=True, - verbose_name="Letzter Aktualisierungszeitpunkt des Caches") - site_cache = models.BooleanField(default=False, verbose_name="Seitencache?") - needed_until = models.DateField(default=None, null=True, blank=True, verbose_name="Benötigt bis") - - class Meta: - verbose_name = "Cacheeintrag" - verbose_name_plural = "Cacheeinträge" - - def __str__(self): - return self.name or self.id - - def update(self, new_value): - if not self.site_cache: - self.last_time_updated = timezone.now() - cache.set(self.id, new_value, self.expiration_time) - self.save() - - def get(self): - if not self.site_cache: - return cache.get(self.id, False) - else: - return None - - def is_expired(self) -> bool: - """ - Checks whether a cache is expired - :return: Is cache expired? - """ - # If cache never was updated it have to - if self.last_time_updated is None: - return True - - # Else check if now is bigger than last time updated + expiration time - delta = datetime.timedelta(seconds=self.expiration_time) - return timezone.now() > self.last_time_updated + delta - - def is_needed(self) -> bool: - """ - Checks whether a plan can be deleted - :return: Is cache needed? - """ - if self.needed_until is None: - return True - elif timezone.now().date() > self.needed_until: - return False - else: - return True - - def delete(self, *args, **kwargs): - """Overrides model function delete to delete cache entry, too""" - cache.delete(self.id) - super(Cache, self).delete(*args, **kwargs) - - def decorator(self, func): - decorator_cache = self - - def wrapper(*args, **kwargs): - if "force_update" in kwargs: - force_update = kwargs["force_update"] - del kwargs["force_update"] - else: - force_update = False - cached = decorator_cache.get() - if cached is not False and not force_update: - print("CACHED VALUE FOR ", func) - return cached - - print("NON CACHED VALUE FOR ", func, "FORCE", force_update) - res = func(*args, **kwargs) - decorator_cache.update(res) - return res - - return wrapper diff --git a/biscuit/core/dashboard/plan_caches.py b/biscuit/core/dashboard/plan_caches.py deleted file mode 100644 index 9b22a3293e8467fe0842e75ec37abefbe59761ed..0000000000000000000000000000000000000000 --- a/biscuit/core/dashboard/plan_caches.py +++ /dev/null @@ -1,51 +0,0 @@ -import datetime -from django.utils import timezone -from dashboard.caches import EXPIRATION_TIME_CACHE_FOR_PLAN_CACHES -from untisconnect.drive import drive, TYPE_TEACHER, TYPE_CLASS, Cache -from untisconnect.api_helper import date_to_untis_date - - -def get_cache_for_plan(type: int, id: int, smart: bool = False, monday_of_week=None) -> Cache: - """ - Creates a Cache for a plan with given params - :param type: TYPE_TEACHER, TYPE_CLASS or TYPE_ROOM - :param id: database id of plan - :param smart: Is smart? - :param monday_of_week: Monday of needed week (if smart) - :return: Cache object - """ - - # Create unique id for plan cache - cache_id = "plan_{}_{}{}".format(type, id, "_smart" if smart else "") - - # Decide which type of plan - if type == TYPE_TEACHER: - idx = "teachers" - elif type == TYPE_CLASS: - idx = "classes" - else: - idx = "rooms" - - # Set name for cache entry - name = "Stundenplan für {}".format(drive[idx][id]) - - needed_until = timezone.now().date() + datetime.timedelta(days=1) - if smart: - # Add date to cache id and name if smart plan - cache_id += "_" + date_to_untis_date(monday_of_week) - name += ", " + date_to_untis_date(monday_of_week) - - # Set time after which cache will be deleted - needed_until = monday_of_week + datetime.timedelta(days=4) - - # Create new cache entry - cache = Cache.objects.get_or_create(id=cache_id)[0] - - # Set expiration time and name to cache entry - if cache.expiration_time != EXPIRATION_TIME_CACHE_FOR_PLAN_CACHES.expiration_time or cache.name != name: - cache.expiration_time = EXPIRATION_TIME_CACHE_FOR_PLAN_CACHES.expiration_time - cache.name = name - cache.needed_until = needed_until - cache.save() - - return cache diff --git a/biscuit/core/dashboard/templates/dashboard/tools.html b/biscuit/core/dashboard/templates/dashboard/tools.html deleted file mode 100644 index cce11ff3de4d0eccb06203b18d431f6a6b544a91..0000000000000000000000000000000000000000 --- a/biscuit/core/dashboard/templates/dashboard/tools.html +++ /dev/null @@ -1,76 +0,0 @@ -{% include 'partials/header.html' %} -{% load msg_box %} -<main> - <h4>Tools</h4> - <div class="card"> - <div class="card-content"> - <span class="card-title"> - Cache-Management - </span> - {% msg_box "Nach Änderung der Ablaufzeit muss der entsprechende Cache (bei Variablencaches) bzw. der gesamte Cache (bei Sitecaches) geleert werden, damit die Änderung wirksam wird." "warning" "warning" %} - <table class="highlight"> - <thead> - <tr> - <th>ID</th> - <th>Name</th> - <th>Typ</th> - <th>Ablaufzeit</th> - <th>Letzter Aktualisierungszeitpunkt des Caches</th> - <th>Aktionen</th> - </tr> - </thead> - <tbody> - {% for cache in caches %} - <tr> - <td> - <pre>{{ cache.id }}</pre> - </td> - <td>{{ cache.name }}</td> - <td> - <span class="badge new">{{ cache.site_cache|yesno:"Seitencache,Variablencache" }}</span> - </td> - - <td>{{ cache.expiration_time }} s</td> - <td> - {% if cache.site_cache %} - k. A. - {% else %} - {{ cache.last_time_updated }} - {% if cache.is_expired %} - <span class="badge new red">Abgelaufen</span> - {% else %} - <span class="badge new green">Gültig</span> - {% endif %} - {% endif %} - </td> - <td> - {% if not cache.site_cache %} - <a class="btn-flat waves-effect waves-red red-text" - href="{% url "tools_clear_single_cache" cache.id %}"> - <i class="material-icons left">delete</i> Cache leeren - </a> - {% endif %} - <a class="btn-flat waves-effect waves-orange orange-text" - href="{% url "admin:dashboard_cache_change" cache.id %}" target="_blank"> - <i class="material-icons left">edit</i> - Ablaufzeit bearbeiten - </a> - - </td> - </tr> - {% endfor %} - </tbody> - </table> - {% if msg == "success_cleared_whole_cache" %} - {% msg_box "Der gesamte Cache wurde erfolgreich geleert." "success" "check_circle" %} - {% elif msg == "success_cleared_single_cache" %} - {% msg_box "Ein Cache wurde erfolgreich geleert." "success" "check_circle" %} - {% endif %} - </div> - <div class="card-action"> - <a href="{% url "tools_clear_cache" %}">Cache leeren</a> - </div> - </div> -</main> - -{% include 'partials/footer.html' %} diff --git a/biscuit/core/dashboard/urls.py b/biscuit/core/dashboard/urls.py index b8b08c524694d3efb13566caf7a4b539195066d2..18c13061822957f21d4f87a51497170e392683ae 100644 --- a/biscuit/core/dashboard/urls.py +++ b/biscuit/core/dashboard/urls.py @@ -27,8 +27,5 @@ import dashboard.views.tools as tools_views urlpatterns += [ path('offline', tools_views.offline, name='offline'), - path("tools", tools_views.tools, name="tools"), - path("tools/clear-cache", tools_views.tools_clear_cache, name="tools_clear_cache"), - path("tools/clear-cache/<str:id>", tools_views.tools_clear_cache, name="tools_clear_single_cache"), path('about/', tools_views.about, name='about') ] diff --git a/biscuit/core/dashboard/views/tools.py b/biscuit/core/dashboard/views/tools.py index 42d116cffcf82837c872195fdaf488d276447630..0bcdee0d52aafc23e1e99b82d42687a9f55ee708 100644 --- a/biscuit/core/dashboard/views/tools.py +++ b/biscuit/core/dashboard/views/tools.py @@ -1,9 +1,5 @@ -from django.contrib.auth.decorators import login_required, user_passes_test -from django.core.cache import cache -from django.shortcuts import render, redirect -from django.urls import reverse +from django.shortcuts import render -from dashboard.models import Cache from meta import OPEN_SOURCE_COMPONENTS @@ -13,33 +9,3 @@ def offline(request): def about(request): return render(request, "common/about.html", context={"components": OPEN_SOURCE_COMPONENTS}) - - -@login_required -@user_passes_test(lambda u: u.is_superuser) -def tools(request): - msg = None - if request.session.get("msg", False): - msg = request.session["msg"] - request.session["msg"] = None - - caches = Cache.objects.all() - context = { - "msg": msg, - "caches": caches - } - return render(request, "dashboard/tools.html", context) - - -@login_required -def tools_clear_cache(request, id=None): - if id is not None: - cache.delete(id) - request.session["msg"] = "success_cleared_single_cache" - print("[IMPORTANT] Single cache cleared!") - else: - cache.clear() - request.session["msg"] = "success_cleared_whole_cache" - print("[IMPORTANT] Whole cache cleared!") - - return redirect(reverse("tools")) diff --git a/biscuit/core/static/common/helper.js b/biscuit/core/static/common/helper.js index 2b6837838df14525bf203a3e5b2d4ed2bfd76cb2..d68574fde82f6cbd94100f5ce2f2731d04d7ca68 100644 --- a/biscuit/core/static/common/helper.js +++ b/biscuit/core/static/common/helper.js @@ -25,88 +25,3 @@ function getNowFormatted() { } -function selectActiveLink() { - var currlocation = $('meta[name="active-loaction"]'); - var url_name = currlocation.attr("content"); - //console.log(url_name); - - var selector = ".url-" + url_name; - console.log(selector); - $(selector).addClass("active"); - $(selector).parent().parent().parent().addClass("active"); -} - -$(document).ready(function () { - selectActiveLink(); - - $("dmc-datetime input").addClass("datepicker"); - $("[data-form-control='date']").addClass("datepicker"); - $("[data-form-control='time']").addClass("timepicker"); - - // Initialize sidenav [MAT] - $(".sidenav").sidenav(); - - // Initialize datepicker [MAT] - $('.datepicker').datepicker({ - format: 'dd.mm.yyyy', - // Translate to German - i18n: { - months: ['Januar', 'Februar', 'März', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember'], - monthsShort: ['Jan', 'Feb', 'Mär', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez'], - weekdays: ['Sonntag', 'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag'], - weekdaysShort: ['So', 'Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa'], - weekdaysAbbrev: ['S', 'M', 'D', 'M', 'D', 'F', 'S'], - - // Buttons - today: 'Heute', - cancel: 'Abbrechen', - done: 'OK', - }, - - // Set monday as first day of week - firstDay: 1, - autoClose: true - }); - - // Initialize timepicker [MAT] - $('.timepicker').timepicker({ - twelveHour: false, - autoClose: true, - i18n: { - cancel: 'Abbrechen', - clear: 'Löschen', - done: 'OK' - }, - }); - - // Initialize tooltip [MAT] - $('.tooltipped').tooltip(); - - // Initialize select [MAT] - $('select').formSelect(); - - // Initalize print button - $("#print").click(function () { - window.print(); - }); - - // Initialize Collapsible [MAT] - $('.collapsible').collapsible(); - - // Initialize FABs [MAT] - $('.fixed-action-btn').floatingActionButton(); - - // Initialize Modals [MAT] - $('.modal').modal(); - - // Initialize delete button - $(".delete-button").click(function (e) { - if (!confirm("Wirklich löschen?")) { - e.preventDefault(); - } - }); - - if (typeof onFinish !== 'undefined') { - onFinish(); - } -}); diff --git a/biscuit/core/static/common/style.css b/biscuit/core/static/common/style.css deleted file mode 100644 index 780e9fec90ff9d4abcaf22a9482c247d9ed97b49..0000000000000000000000000000000000000000 --- a/biscuit/core/static/common/style.css +++ /dev/null @@ -1,673 +0,0 @@ -/**********/ -/* COMMON */ -/**********/ - -body { - display: flex; - min-height: 100vh; - flex-direction: column; -} - -.primary-color { - background-color: #da1f3d !important; -} - -.primary-color-text, .primary-color-text a { - color: #da1f3d !important; -} - -/**********/ -/* HEADER */ -/**********/ - -.brand-logo { - margin-left: 10px; -} - -/********/ -/* MAIN */ -/********/ - -main { - padding: 10px 20px; - flex: 1 0 auto; -} - -/***********/ -/* SIDENAV */ -/***********/ - -ul.sidenav.sidenav-fixed li.logo { - margin-top: 32px; - margin-bottom: 50px; -} - -ul.sidenav.sidenav-fixed .brand-logo { - margin: 0; -} - -.logo img { - width: 250px; -} - -header a.sidenav-trigger { - position: absolute; - left: 7.5%; - top: 0; - - height: 64px; - font-size: 38px; - - float: none; - - text-align: center; - color: white; - - z-index: 2; -} - - -@media only screen and (max-width: 993px) { - header div.nav-wrapper { - z-index: -5; - } -} - -header, main, footer { - margin-left: 300px; -} - - -.footer-icon { - font-size: 22px !important; - vertical-align: middle; -} - - -@media only screen and (min-width: 1384px) { - .footer-row-large { - display: flex; - align-items: center; - } - - .footer-row-small { - display: none; - } -} - -@media only screen and (max-width: 1383px) { - .footer-row-large { - display: none; - } - - .footer-row-small { - display: block; - } -} - -ul.footer-ul { - display: inline-block; - text-align: right; - float: right; -} - -.make-it-higher { - vertical-align: middle; - line-height: 36px; -} - -@media only screen and (max-width: 992px) { - header, main, footer { - margin-left: 0; - } -} - -/* Collections */ - -ul.collection .collection-item .title { - font-weight: bold; -} - -.section { - padding: 0; -} - -form .row { - margin-top: 0; - margin-bottom: 0; -} - -/* Badges */ - -span.badge.new::after { - content: ""; -} - -span.badge.new { - font-size: 1rem; - line-height: 26px; - height: 26px; -} - -span.badge.new.no-float { - float: none; - padding: 3px 6px; -} - -span.badge .material-icons { - font-size: 0.9rem; -} - -/*+++++++++++*/ -/* Timetable */ -/*+++++++++++*/ -.smart-plan-badge { - margin: 5px 20px 5px 0; -} - -li.active > a > .sidenav-badge { - background-color: whitesmoke !important; - color: #DA3D56 !important; -} - -.timetable-plan .row, .timetable-plan .col { - display: flex; - padding: 0 .25rem; -} - -.timetable-plan .row { - margin-bottom: .25rem; -} - -.lesson-card, .timetable-title-card { - margin: 0; - display: flex; - flex-grow: 1; - min-height: 65px; -} - -.lesson-card .card-content { - padding: 0; - text-align: center; - width: 100%; - height: 100%; - display: flex; - flex-direction: column; -} - -.lesson-card .card-content div { - padding: 3px; - flex: auto; - width: 100%; - display: flex; - align-items: center; - justify-content: center; -} - -.timetable-title-card .card-content { - padding: 10px; - text-align: center; - width: 100%; -} - -.timetable-mobile-title-card { - margin-top: 50px; - margin-bottom: .60rem; -} - -.timetable-mobile-title-card:first-child { - margin-top: -10px; - margin-bottom: .60rem; -} - -.timetable-mobile-title-card .card-content { - padding: 10px; - text-align: center; - width: 100%; -} - -.timetable-mobile-title-card .card-content .card-title { - font-weight: bold; -} - -table.substitutions td, table.substitutions th { - padding: 10px 5px; -} - -.lesson-with-sub { - border: 3px solid red; - border-radius: 3px; -} - -.lesson-with-sub .badge { - margin: 0; -} - -.lesson-with-event { - border: 3px solid #9c27b0; - border-radius: 3px; -} - -.lesson-card a, .substitutions a { - color: inherit; -} - -/*.timetable-time {*/ -/*margin-right: 20px;*/ -/*}*/ - -/*+++++++++*/ -/* Buttons */ -/*+++++++++*/ - -.btn-flat-large { - line-height: 60px; - height: 60px; -} - -.btn-flat-large i { - font-size: 4rem; -} - -.btn-flat-medium { - line-height: 40px; - height: 40px; -} - -.btn-flat-medium i { - font-size: 2rem; -} - -.btn-timetable-quicklaunch { - margin: 1%; - width: 30%; - background-color: rgba(0, 0, 0, 0.05) !important; - color: black; -} - -.btn-timetable-quicklaunch:hover { - background-color: #da1f3d !important; - color: whitesmoke; -} - -.no-margin { - margin: 0 !important; -} - -.valign-middle { - vertical-align: middle; -} - -.valign-top { - vertical-align: top; -} - -.valign-bot { - vertical-align: bottom; -} - -.height-inherit { - height: 100%; -} - -/* Table*/ - -table.striped > tbody > tr:nth-child(odd), table tr.striped { - background-color: rgba(208, 208, 208, 0.5); -} - - -/*+++++++*/ -/* Print */ -/*+++++++*/ -#print-header { - display: none; -} - -.print-icon { - margin-top: 1.52rem; -} - -@media print { - body { - font-size: 15px; - } - - header, main, footer { - margin-left: 0; - } - - ul.sidenav { - display: none !important; - transform: translateX(-105%) !important; - } - - nav { - display: none; - } - - .sidenav-trigger { - display: none; - } - - #print-header { - display: block; - border-bottom: 1px solid; - margin-bottom: 0; - } - - #print-header .col.right-align { - padding: 15px; - } - - main, header { - padding: 0; - } - - footer, footer .footer-copyright, footer .container { - background-color: white !important; - color: black !important; - } - - footer a { - display: none; - } - - .footer-copyright, .footer-copyright .container { - padding: 0 !important; - margin: 0 !important; - } - - .no-print { - display: none; - } -} - -.alert ul, .alert p { - margin: 0; -} - -.alert > p, .alert > div { - margin: 10px; - padding: 10px; - border-left: 5px solid; -} - -.alert.success > p, .alert.success > div { - background-color: #c5e1a5; - border-color: #4caf50; -} - -.alert.error > p, .alert.error > div { - background-color: #ef9a9a; - border-color: #b71c1c; -} - -.alert.primary > p, .alert.primary > div, .alert.info > p, .alert.info > div { - background-color: #ececec; - border-color: #da1f3d; -} - -.alert.warning p, .alert.warning div { - background-color: #ffb74d; - border-color: #e65100; -} - -main .alert p:first-child, main .alert div:first-child { - margin-left: -10px; - margin-right: -10px; -} - -.btn, .btn-large, .btn-small { - background-color: #0f9d58; -} - -.btn:hover, .btn-large:hover, .btn-small { - background-color: #DA1F3D; -} - -/*++++++++++++++++ -FEEDBACK -++++++++++++++++*/ - -.rating { - display: flex; - flex-direction: row-reverse; - flex-wrap: wrap; - width: 100%; - min-width: 150px; - max-width: 600px; - justify-content: flex-end; -} - -@media only screen and (max-width: 992px) { - .rating { - margin-top: 12px; - min-height: 40px; - justify-content: space-around; - } - - ´ -} - -.rating label { - display: flex; - flex: 1; - position: relative; - cursor: pointer; -} - -.rating label:after { - font-family: 'Material Icons'; - -webkit-font-feature-settings: 'liga'; - position: absolute; - color: #777; - top: 0; - left: 0; - width: 100%; - height: 100%; - text-align: center; - font-size: 40px; - content: 'star_border'; -} - -.rating input { - display: none !important; -} - -.rating > input:checked + label:after, -.rating > input:checked ~ label:after { - content: "star"; - color: #FFD700; -} - -.rating > input:hover + label:after, -.rating > input:hover ~ label:after { - content: "star"; - color: #FFD700; -} - -.support-input-mobile label { - line-height: 1rem; -} - -.span-info { - width: 24px; - vertical-align: middle; -} - -i.collapsible-trigger { - margin-right: -10px; - -} - -.collapsible .collapsible-trigger::before { - content: 'arrow_downward'; -} - -.collapsible .collapsible-trigger.v2::before { - content: 'more_vert'; -} - -.collapsible .active .collapsible-trigger::before { - content: 'arrow_upward'; -} - - -.scroll-fix { - max-height: 300px; - overflow: scroll; -} - -.waves-effect.waves-katharineum .waves-ripple { - background-color: rgba(218, 31, 61, 0.65); -} - -.no-margin { - margin: 0 !important; -} - -.no-padding { - padding: 0 !important; -} - -.no-pad-left { - padding-left: 0 !important; -} - -.no-pad-right { - padding-right: 0 !important; -} - -.sidenav a:not(.collapsible-header) { - padding: 0 16px; -} - -ul.sidenav li.logo > a:hover { - background: none !important; -} - -.waves-effect.waves-primary .waves-ripple { - /* The alpha value allows the text and background color - of the button to still show through. */ - background-color: #da1f3d; -} - -.sidenav .collapsible-body > ul:not(.collapsible) > li.active a > i, .sidenav.sidenav-fixed .collapsible-body > ul:not(.collapsible) > li.active a > i { - color: #fff; -} - -.sidenav .collapsible-body > ul:not(.collapsible) > li.active, .sidenav.sidenav-fixed .collapsible-body > ul:not(.collapsible) > li.active { - background-color: #DA3D56; -} - -.card .card-action a:not(.btn):not(.btn-large):not(.btn-small):not(.btn-large):not(.btn-floating) { - color: #da1f3d; -} - -.card .card-action a:not(.btn):not(.btn-large):not(.btn-small):not(.btn-large):not(.btn-floating):hover { - color: #ea4661; -} - -/*section:not(:last-of-type) {*/ -/* border-bottom: solid #bdbdbd 2px;*/ -/*}*/ - -/*++++++++ -+HOLIDAYS+ -++++++++++ */ - -.holiday-badge { - float: left !important; - position: relative; - margin-left: 0% !important; - left: 50%; - transform: translate(-50%); - width: auto; - height: auto !important; - min-height: 26px; -} - -/* Dashboard */ - -.card-action-badge { - float: left !important; - margin-left: 0 !important; - margin-top: -3px; - margin-right: 10px; -} - -.event-card { - padding: 10px; -} - -.event-card .title { - font-size: 18px; - font-weight: 500; -} - - -.flex-row { - display: flex; - flex-wrap: wrap; - align-items: center; - justify-content: space-between; -} - -.hundred-percent { - width: 100%; -} - -.badge-image { - position: absolute; - left: 0; - top: 10px; - z-index: 1; - background-color: #da1f3d; - color: white; - padding: 2px 10px; - border-radius: 0 3px 3px 0; - text-transform: uppercase; - font-weight: 300; -} - -.center-via-flex { - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; -} - -.center2-via-flex { - display: flex; - flex-direction: column; - align-items: center; -} - -.spinner-primary { - border-color: #da1f3d; -} - -.dashboard-cards { - -webkit-column-break-inside: avoid; - column-count: 3; -} - -@media (min-width: 800px) and (max-width: 1460px) { - .dashboard-cards { - column-count: 2; - } -} - -@media (max-width: 800px) { - .dashboard-cards { - column-count: 1; - } -} - - -.dashboard-cards .card { - display: inline-block; - overflow: visible; - width: 100%; -} diff --git a/biscuit/core/static/js/dashboard.js b/biscuit/core/static/js/dashboard.js deleted file mode 100644 index 1604cae664f8a80628172763611379c01a65bd85..0000000000000000000000000000000000000000 --- a/biscuit/core/static/js/dashboard.js +++ /dev/null @@ -1,601 +0,0 @@ -/*** THIS FILE IS GENERATED from react/src/dashboard.js ***/ - -var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); - -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - -function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } - -function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } - -var REFRESH_TIME = 15; - -// function WithCheckCircleIcon(props) { -// return <div className={"col s12"}> -// <i className={"material-icons left green-text"}>check_circle</i> -// {props.children} -// </div> -// } - -var Dashboard = function (_React$Component) { - _inherits(Dashboard, _React$Component); - - function Dashboard() { - _classCallCheck(this, Dashboard); - - var _this = _possibleConstructorReturn(this, (Dashboard.__proto__ || Object.getPrototypeOf(Dashboard)).call(this)); - - _this.updateRefreshTime = function () { - if (_this.state.refreshIn >= 1) { - if (_this.state.timeout) { - window.clearTimeout(_this.state.timeout); - } - var timeout = window.setTimeout(_this.updateRefreshTime, 1000); - _this.setState({ refreshIn: _this.state.refreshIn - 1, timeout: timeout }); - } else { - _this.updateData(); - } - }; - - _this.updateData = function () { - if (_this.state.networkProblems) { - _this.setState({isLoading: true, networkProblems: false}); - } - - var that = _this; - $.getJSON(API_URL, function (data) { - console.log(data); - if (data) { - that.setState(Object.assign({}, data, {refreshIn: REFRESH_TIME + 1, isLoading: false})); - that.updateRefreshTime(); - } - }).fail(function () { - console.log("error"); - that.setState({refreshIn: REFRESH_TIME + 1, networkProblems: true}); - }); - $.getJSON(API_URL + "/my-plan", function (data) { - console.log(data); - if (data && data.lessons) { - that.setState({lessons: data.lessons, holiday: data.holiday}); - } - }).fail(function () { - console.log("error"); - that.setState({networkProblems: true}); - }); - }; - - _this.state = { - refreshIn: REFRESH_TIME, - isLoading: true, - networkProblems: false - }; - return _this; - } - - _createClass(Dashboard, [{ - key: "componentDidMount", - value: function componentDidMount() { - console.log(API_URL); - this.updateData(); - } - }, { - key: "closeNotification", - value: function closeNotification(notification) { - console.log(notification); - $("#not-" + notification.id).addClass("scale-out"); - window.setTimeout(function () { - $("#not-" + notification.id).hide(); - }, 200); - $.getJSON(API_URL + "/notifications/read/" + notification.id); - this.updateData(); - this.setState({ time: new Date() }); - } - }, { - key: "render", - value: function render() { - if (this.state.networkProblems) { - // Show loading screen until first data are loaded - return React.createElement( - "div", - {className: "row center-via-flex container", style: {"height": "20em"}}, - React.createElement( - "i", - {className: "material-icons large"}, - "signal_wifi_off" - ), - React.createElement( - "p", - {className: "flow-text text-center"}, - "Es ist ein Fehler bei der Netzwerkverbindung aufgetreten." - ), - React.createElement( - "button", - {className: "btn-flat grey-text", onClick: this.updateData}, - "Erneuter Versuch in ", - this.state.refreshIn, - " s" - ) - ); - } - - if (this.state.isLoading) { - // Show loading screen until first data are loaded - return React.createElement( - "div", - {className: "row center-via-flex container", style: {"height": "15em"}}, - React.createElement( - "div", - {className: "center2-via-flex"}, - React.createElement( - "div", - { className: "preloader-wrapper big active" }, - React.createElement( - "div", - { className: "spinner-layer spinner-primary" }, - React.createElement( - "div", - { className: "circle-clipper left" }, - React.createElement("div", { className: "circle" }) - ), - React.createElement( - "div", - { className: "gap-patch" }, - React.createElement("div", { className: "circle" }) - ), - React.createElement( - "div", - { className: "circle-clipper right" }, - React.createElement("div", { className: "circle" }) - ) - ) - ), - React.createElement( - "p", - { className: "text-center flow-text" }, - "Deine aktuellen Informationen werden geladen \u2026" - ) - ) - ); - } - - var that = this; - return React.createElement( - "div", - null, - React.createElement( - "button", - { className: "btn-flat right grey-text", onClick: this.updateData }, - React.createElement( - "i", - { className: "material-icons left" }, - "refresh" - ), - "in ", - this.state.refreshIn, - " s" - ), - React.createElement( - "p", - { className: "flow-text" }, - "Moin Moin, ", - this.state.user.full_name !== "" ? this.state.user.full_name : this.state.user.username, - ". Hier findest du alle aktuellen Informationen:" - ), - React.createElement( - "div", - { className: "alert success" }, - React.createElement( - "p", - null, - React.createElement( - "i", - { className: "material-icons left" }, - "report_problem" - ), - "Das neue Dashboard von SchoolApps befindet sich momentan in der ", - React.createElement( - "strong", - null, - "Testphase" - ), - ". Falls Fehler auftreten oder du einen Verbesserungsvorschlag f\xFCr uns hast, schreibe uns bitte unter ", - React.createElement( - "a", - { - href: "mailto:support@katharineum.de" }, - "support@katharineum.de" - ), - "." - ) - ), - this.state.unread_notifications && this.state.unread_notifications.length > 0 ? this.state.unread_notifications.map(function (notification) { - return React.createElement( - "div", - { className: "alert primary scale-transition", id: "not-" + notification.id, - key: notification.id }, - React.createElement( - "div", - null, - React.createElement( - "i", - { className: "material-icons left" }, - "info" - ), - React.createElement( - "div", - { className: "right" }, - React.createElement( - "button", - { className: "btn-flat", onClick: function onClick() { - return that.closeNotification(notification); - } }, - React.createElement( - "i", - { className: "material-icons center" }, - "close" - ) - ) - ), - React.createElement( - "strong", - null, - notification.title - ), - React.createElement( - "p", - null, - notification.description - ) - ) - ); - }) : "", - this.state.plan && this.state.plan.hints.length > 0 ? React.createElement( - "div", - null, - this.state.plan.hints.map(function (hint, idx) { - return React.createElement( - "div", - { className: "alert primary", key: idx }, - React.createElement( - "div", - null, - React.createElement( - "em", - { className: "right hide-on-small-and-down" }, - "Hinweis f\xFCr ", - that.state.date_formatted - ), - React.createElement( - "i", - { className: "material-icons left" }, - "announcement" - ), - React.createElement("p", { dangerouslySetInnerHTML: { __html: hint.html } }), - React.createElement( - "em", - { className: "hide-on-med-and-up" }, - "Hinweis f\xFCr ", - that.state.date_formatted - ) - ) - ); - }) - ) : "", - React.createElement( - "div", - { className: "row" }, - this.state.has_plan ? React.createElement( - "div", - {className: "col s12 m12 l6 xl4"}, - React.createElement( - "div", - {className: "card"}, - React.createElement( - "div", - {className: "card-content"}, - React.createElement( - "span", - {className: "card-title"}, - "Plan ", - this.state.plan.type === 2 ? "der" : "für", - " ", - React.createElement( - "em", - null, - this.state.plan.name - ), - " f\xFCr ", - this.state.date_formatted - ), - this.state.holiday ? React.createElement( - "div", - { className: "card" }, - React.createElement( - "div", - { className: "card-content" }, - React.createElement( - "span", - { - className: "badge new blue center-align holiday-badge" }, - this.state.holiday.name - ), - React.createElement("br", null) - ) - ) : this.state.lessons && this.state.lessons.length > 0 ? React.createElement( - "div", - { className: "timetable-plan" }, - this.state.lessons.map(function (lesson) { - // Show one lesson row - return React.createElement( - "div", - { className: "row" }, - React.createElement( - "div", - { className: "col s4" }, - React.createElement( - "div", - { className: "card timetable-title-card" }, - React.createElement( - "div", - { className: "card-content" }, - React.createElement( - "span", - { className: "card-title left" }, - lesson.time.number_format - ), - React.createElement( - "div", - { - className: "right timetable-time grey-text text-darken-2" }, - React.createElement( - "span", - null, - lesson.time.start_format - ), - React.createElement("br", null), - React.createElement( - "span", - null, - lesson.time.end_format - ) - ) - ) - ) - ), - React.createElement("div", { className: "col s8", - dangerouslySetInnerHTML: { __html: lesson.html } }) - ); - }) - ) : "" - ), - React.createElement( - "div", - { className: "card-action" }, - React.createElement( - "a", - { href: MY_PLAN_URL }, - React.createElement( - "span", - { className: "badge new primary-color card-action-badge" }, - "SMART PLAN" - ), - "anzeigen" - ) - ) - ) - ) : "", - this.state.current_events && this.state.current_events.length > 0 ? React.createElement( - "div", - {className: "col s12 m12 l6 xl4"}, - React.createElement( - "div", - {className: "card "}, - React.createElement( - "div", - {className: "card-content"}, - React.createElement( - "span", - {className: "card-title"}, - "Aktuelle Termine" - ), - this.state.current_events.map(function (event) { - return React.createElement( - "div", - { className: "card-panel event-card" }, - React.createElement( - "span", - { className: "title" }, - event.name - ), - React.createElement("br", null), - event.formatted - ); - }) - ), - React.createElement( - "div", - { className: "card-action" }, - React.createElement( - "a", - { href: "https://katharineum-zu-luebeck.de/aktuelles/termine/", target: "_blank" }, - "Weitere Termine" - ) - ) - ) - ) : "", - this.state.newest_article ? React.createElement( - "div", - {className: "col s12 m12 l6 xl4"}, - React.createElement( - "div", - {className: "card"}, - React.createElement( - "div", - {className: "card-image"}, - React.createElement( - "span", - {className: "badge-image z-depth-2"}, - "Aktuelles von der Homepage" - ), - React.createElement("img", { - src: this.state.newest_article.image_url, - alt: this.state.newest_article.title - }) - ), - React.createElement( - "div", - {className: "card-content"}, - React.createElement("span", { - className: "card-title", - dangerouslySetInnerHTML: {__html: this.state.newest_article.title} - }), - React.createElement("p", {dangerouslySetInnerHTML: {__html: this.state.newest_article.short_text}}) - ), - React.createElement( - "div", - {className: "card-action"}, - React.createElement( - "a", - {href: this.state.newest_article.link, target: "_blank"}, - "Mehr lesen" - ) - ) - ), - React.createElement( - "a", - { - className: "btn hundred-percent primary-color", - href: "https://katharineum-zu-luebeck.de/", - target: "_blank" - }, - "Weitere Artikel", - React.createElement( - "i", - {className: "material-icons right"}, - "arrow_forward" - ) - ) - ) : "" - ), - React.createElement( - "div", - { className: "row" }, - React.createElement( - "div", - { className: "col s12 m6" }, - React.createElement( - "h5", - null, - "Letzte Aktivit\xE4ten" - ), - this.state.activities && this.state.activities.length > 0 ? React.createElement( - "ul", - { className: "collection" }, - this.state.activities.map(function (activity) { - return React.createElement( - "li", - { className: "collection-item", key: activity.id }, - React.createElement( - "span", - { className: "badge new primary-color" }, - activity.app - ), - React.createElement( - "span", - { className: "title" }, - activity.title - ), - React.createElement( - "p", - null, - React.createElement( - "i", - { className: "material-icons left" }, - "access_time" - ), - " ", - activity.created_at - ), - React.createElement( - "p", - null, - activity.description - ) - ); - }) - ) : React.createElement( - "p", - null, - "Noch keine Aktivit\xE4ten vorhanden." - ) - ), - React.createElement( - "div", - { className: "col s12 m6" }, - React.createElement( - "h5", - null, - "Letzte Benachrichtigungen" - ), - this.state.notifications && this.state.notifications.length > 0 ? React.createElement( - "ul", - { className: "collection" }, - this.state.notifications.map(function (notification) { - return React.createElement( - "li", - { className: "collection-item", key: notification.id }, - React.createElement( - "span", - { className: "badge new primary-color" }, - notification.app - ), - React.createElement( - "span", - { className: "title" }, - notification.title - ), - React.createElement( - "p", - null, - React.createElement( - "i", - { className: "material-icons left" }, - "access_time" - ), - " ", - notification.created_at - ), - React.createElement( - "p", - null, - notification.description - ), - notification.link ? React.createElement( - "p", - null, - React.createElement( - "a", - { href: notification.link }, - "Mehr Informationen \u2192" - ) - ) : "" - ); - }) - ) : React.createElement( - "p", - null, - "Noch keine Benachrichtigungen vorhanden." - ) - ) - ) - ); - } - }]); - - return Dashboard; -}(React.Component); - -$(document).ready(function () { - var domContainer = document.querySelector('#dashboard_container'); - ReactDOM.render(React.createElement(Dashboard, null), domContainer); -}); diff --git a/biscuit/core/static/js/rebus.js b/biscuit/core/static/js/rebus.js deleted file mode 100644 index 752008a3dc5b7e2e43261ea7bf0ada5b51e65722..0000000000000000000000000000000000000000 --- a/biscuit/core/static/js/rebus.js +++ /dev/null @@ -1,642 +0,0 @@ -/*** THIS FILE IS GENERATED from react/src/rebus.js ***/ - -var _createClass = function () { - function defineProperties(target, props) { - for (var i = 0; i < props.length; i++) { - var descriptor = props[i]; - descriptor.enumerable = descriptor.enumerable || false; - descriptor.configurable = true; - if ("value" in descriptor) descriptor.writable = true; - Object.defineProperty(target, descriptor.key, descriptor); - } - } - - return function (Constructor, protoProps, staticProps) { - if (protoProps) defineProperties(Constructor.prototype, protoProps); - if (staticProps) defineProperties(Constructor, staticProps); - return Constructor; - }; -}(); - -function _classCallCheck(instance, Constructor) { - if (!(instance instanceof Constructor)) { - throw new TypeError("Cannot call a class as a function"); - } -} - -function _possibleConstructorReturn(self, call) { - if (!self) { - throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); - } - return call && (typeof call === "object" || typeof call === "function") ? call : self; -} - -function _inherits(subClass, superClass) { - if (typeof superClass !== "function" && superClass !== null) { - throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); - } - subClass.prototype = Object.create(superClass && superClass.prototype, { - constructor: { - value: subClass, - enumerable: false, - writable: true, - configurable: true - } - }); - if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; -} - -var OPTIONS_ONLINE_COMMON = ["Portal ist nicht erreichbar", "Fehlermeldung(en) tauchen auf", "Anmeldung funktioniert nicht", "Zugangsdaten vergessen"]; - -var BASIC_OPTIONS = [{ - id: "infrastructureIssues", - name: "Infrastrukturprobleme", - options: [{ - id: "presentationDeviceIssue", - name: "Problem mit Beamer/Fernseher", - helpText: "Bitte wähle aus, wo der Beamer bzw. Fernseher steht!" - }, { - id: "printerIssue", - name: "Problem mit einem Drucker", - helpText: "Bitte nenne uns in der Beschreibung das Modell des Druckers, damit wir genau wissen, welchen Drucker du meinst!" - }, { - id: "subMonitorIssue", - name: "Vertretungsplanmonitor funktioniert nicht", - helpText: "Nenne uns bitte in der Beschreibung ggf. weitere Informationen!" - }, { - id: "aulaIssue", - name: "Problem in der Aula (→Technik-AG)", - helpText: "Deine Anfrage wird direkt an die Technik-AG weitergeleitet." - }, { - id: "wlanIssue", - name: "Probleme mit dem Schul-WLAN (kath-schueler/lehrer)", - helpText: "Nenne uns bitte unbedingt auch den Ort in der Schule, an dem das Problem auftrat." - }] -}, { - id: "onlineIssues", - name: "Webservices", - options: [{ - id: "forum", - name: "Forum (ILIAS)", - options: OPTIONS_ONLINE_COMMON.concat(["Ich kann meinen Kurs bzw. Klasse nicht sehen/finden.", "Ich kann keine Dateien hochladen.", "Es taucht eine weiße Seite auf.", "Ich habe falsche Informationen gefunden."]) - }, { - id: "mail", - name: "Webmail/Mailserver", - options: OPTIONS_ONLINE_COMMON.concat(["Mein E-Mail-Programm funktioniert mit meiner …@katharineum.de-Adresse nicht.", "Ich bekomme keine E-Mails bzw. kann keine senden."]) - }, { - id: "schoolapps", - name: "SchoolApps", - options: OPTIONS_ONLINE_COMMON.concat(["Der Stundenplan/Vertretungsplan ist falsch.", "Ich bin der falschen Klasse zugeordnet.", "Ich habe einen Fehler gefunden."]) - }, { - id: "subOrMenu", - name: "Vertretungsplan/Speiseplan", - options: OPTIONS_ONLINE_COMMON.concat(["Kein Vertretungsplan zu sehen", "Falscher Vertretungsplan zu sehen", "Kein Speiseplan zu sehen", "Falscher Speiseplan zu sehen"]) - }, { - id: "website", - name: "Website (katharineum-zu-luebeck.de)", - options: ["Website nicht erreichbar", "Falsche Inhalte vorhanden", "Typografiefehler"] - - }, { - id: "otherOnlineIssue", - name: "Andere Anwendung" - }] -}, { - id: "deviceIssues", - name: "Probleme am Computer/Notebook", - options: [{ - id: "loginIssue", - name: "Anmeldeproblem/Passwort vergessen" - }, { - id: "internetIssue", - name: "Internetproblem" - }, { - id: "noReaction", - name: "Programm-/Computerabsturz (keine Reaktion)" - }, { - id: "powerOffNoBoot", - name: "Computer/Notebook ist ausgegangen/startet nicht" - }, { - id: "speedIssue", - name: "Computer/Notebook zu langsam" - }, { - id: "noUSB", - name: "USB-Stick wird nicht erkannt" - }, { - id: "noOpenTray", - name: "CD/DVD-Laufwerk öffnet sich nicht" - }, { - id: "noCDDVD", - name: "CD/DVD wird nicht erkannt/abgespielt" - }, { - id: "keyboardMouse", - name: "Tastatur/Maus funktioniert nicht" - }, { - id: "missingHardware", - name: "Tastatur/Maus/Lautsprecher/etc. fehlt" - }, { - id: "missingKeys", - name: "Fehlende Tasten auf der Tastatur" - }, { - id: "hardwareMisc", - name: "Andere Hardware defekt / Äußere Schäden" - }] -}, { - id: "otherIssues", - name: "Andere Probleme", - options: [{ - id: "extra", - name: "Sonstiges" - }] -}]; - -var OTHER_LOCATIONS = ["Notebookwagen 1. Stock/R 2.06", "Notebookwagen 2. Stock/R 2.10", "Notebookwagen 3. Stock/Physik", "Internetcafe", "Infopoint/Sekretariatsvorraum", "Lehrerzimmer (Vorraum)", "Lehrerzimmer (Hauptraum)"]; - -function getCategoryOfOption(option) { - var _iteratorNormalCompletion = true; - var _didIteratorError = false; - var _iteratorError = undefined; - - try { - for (var _iterator = BASIC_OPTIONS[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { - var category = _step.value; - - // console.log(category); - var _iteratorNormalCompletion2 = true; - var _didIteratorError2 = false; - var _iteratorError2 = undefined; - - try { - for (var _iterator2 = category.options[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { - var opt = _step2.value; - - // console.log(opt); - if (opt.id === option) { - return category.id; - } - } - } catch (err) { - _didIteratorError2 = true; - _iteratorError2 = err; - } finally { - try { - if (!_iteratorNormalCompletion2 && _iterator2.return) { - _iterator2.return(); - } - } finally { - if (_didIteratorError2) { - throw _iteratorError2; - } - } - } - } - } catch (err) { - _didIteratorError = true; - _iteratorError = err; - } finally { - try { - if (!_iteratorNormalCompletion && _iterator.return) { - _iterator.return(); - } - } finally { - if (_didIteratorError) { - throw _iteratorError; - } - } - } -} - -function getOption(option) { - var _iteratorNormalCompletion3 = true; - var _didIteratorError3 = false; - var _iteratorError3 = undefined; - - try { - for (var _iterator3 = BASIC_OPTIONS[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) { - var category = _step3.value; - var _iteratorNormalCompletion4 = true; - var _didIteratorError4 = false; - var _iteratorError4 = undefined; - - try { - for (var _iterator4 = category.options[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) { - var opt = _step4.value; - - if (opt.id === option) { - return opt; - } - } - } catch (err) { - _didIteratorError4 = true; - _iteratorError4 = err; - } finally { - try { - if (!_iteratorNormalCompletion4 && _iterator4.return) { - _iterator4.return(); - } - } finally { - if (_didIteratorError4) { - throw _iteratorError4; - } - } - } - } - } catch (err) { - _didIteratorError3 = true; - _iteratorError3 = err; - } finally { - try { - if (!_iteratorNormalCompletion3 && _iterator3.return) { - _iterator3.return(); - } - } finally { - if (_didIteratorError3) { - throw _iteratorError3; - } - } - } -} - -var Select = function (_React$Component) { - _inherits(Select, _React$Component); - - function Select() { - _classCallCheck(this, Select); - - return _possibleConstructorReturn(this, (Select.__proto__ || Object.getPrototypeOf(Select)).apply(this, arguments)); - } - - _createClass(Select, [{ - key: "render", - value: function render() { - return React.createElement( - "select", - {onChange: this.props.onChange, defaultValue: "no", required: this.props.show}, - React.createElement( - "option", - {value: "no", disabled: true}, - "Nichts ausgew\xE4hlt" - ), - this.props.values.map(function (val, i) { - return React.createElement( - "option", - {value: val, key: i}, - val - ); - }), - React.createElement( - "option", - {value: "extra"}, - this.props.defaultValue - ) - ); - } - }]); - - return Select; -}(React.Component); - -Select.propTypes = { - onChange: PropTypes.func.isRequired, - values: PropTypes.array.isRequired, - defaultValue: PropTypes.string, - show: PropTypes.bool.isRequired - -}; - -Select.defaultProps = { - defaultValue: "Sonstiges" -}; - -var Input = function (_React$Component2) { - _inherits(Input, _React$Component2); - - function Input() { - _classCallCheck(this, Input); - - return _possibleConstructorReturn(this, (Input.__proto__ || Object.getPrototypeOf(Input)).apply(this, arguments)); - } - - _createClass(Input, [{ - key: "render", - value: function render() { - return React.createElement( - "div", - { - className: (this.props.show ? "" : "hide ") + "input-field col s12 m12 l4" - }, - React.createElement( - "i", - {className: "material-icons prefix"}, - this.props.icon - ), - this.props.children, - React.createElement( - "label", - null, - this.props.label - ) - ); - } - }]); - - return Input; -}(React.Component); - -Input.propTypes = { - icon: PropTypes.string, - show: PropTypes.bool, - label: PropTypes.string.isRequired, - children: PropTypes.object.isRequired -}; - -Input.defaultProps = { - icon: "list", - show: false -}; - -var REBUSDynSelect = function (_React$Component3) { - _inherits(REBUSDynSelect, _React$Component3); - - function REBUSDynSelect() { - _classCallCheck(this, REBUSDynSelect); - - var _this3 = _possibleConstructorReturn(this, (REBUSDynSelect.__proto__ || Object.getPrototypeOf(REBUSDynSelect)).call(this)); - - _this3._onCategoryChanges = function (e) { - var opt = e.target.value; - var category = getCategoryOfOption(opt); - var option = getOption(opt); - - // Get matching helper text - var helpText = option.helpText || _this3.state.helpText; - if (category === "deviceIssues") { - helpText = "Wähle bitte das Gerät mit dem Problem aus! Bitte vergiss nicht, uns das Problem unten genauer zu beschreiben!"; - } else if (category === "onlineIssues") { - helpText = "Bitte konkretisiere das Problem durch eine Auswahl und gib bitte unten genauere Informationen an."; - } else if (category === "otherIssues") { - helpText = "Da es sich scheinbar um ein seltenes oder noch nicht erfasstes Problem handelt, gib uns bitte besonders viele Informationen."; - } - - // Update state - _this3.setState({ - selectedCategory: category, - selectedOption: option, - step: 1, - helpText: helpText - }); - }; - - _this3._onSetB = function (e) { - var val = e.target.value; - _this3.setState({ - valueB: val, - step: 2 - }); - }; - - _this3._onSetC = function (e) { - var val = e.target.value; - _this3.setState({ - valueC: val, - step: 2 - }); - }; - - _this3.state = { - selectedCategory: "noCategory", - selectedOption: null, - helpText: "Wähle bitte eine Kategorie aus!", - valueB: "", - valueC: "", - step: 0 - }; - return _this3; - } - - _createClass(REBUSDynSelect, [{ - key: "componentDidMount", - value: function componentDidMount() { - // Init materialize selects - var elems = document.querySelectorAll('select'); - M.FormSelect.init(elems, {}); - } - }, { - key: "render", - value: function render() { - var LOCATIONS = this.props.rooms.concat(OTHER_LOCATIONS); - var LOCATIONS_WITH_POSSIBLE_PRESENTATION_DEVICE = this.props.rooms; - LOCATIONS.sort(); - - // console.log(this.state); - var that = this; - var sC = this.state.selectedCategory; - var sO = this.state.selectedOption ? this.state.selectedOption.id : null; - var step = this.state.step; - // console.log(BASIC_OPTIONS[2].options); - return React.createElement( - "div", - {className: "App"}, - React.createElement( - "div", - {className: "row"}, - React.createElement( - "div", - { - className: "input-field col s12 m12 l4" - }, - React.createElement( - "i", - {className: "material-icons prefix"}, - "list" - ), - React.createElement( - "select", - { - onChange: this._onCategoryChanges, defaultValue: "noCategory", className: "validate", - required: true - }, - "-", - React.createElement( - "option", - {value: "noCategory", disabled: true}, - "Keine Kategorie ausgew\xE4hlt" - ), - BASIC_OPTIONS.map(function (category) { - return React.createElement( - "optgroup", - {label: category.name, key: category.id}, - category.options.map(function (option) { - return React.createElement( - "option", - {value: option.id, key: option.id}, - option.name - ); - }) - ); - }) - ), - React.createElement( - "label", - null, - "Kategorie" - ) - ), - React.createElement( - Input, - {label: "Ort des Computer/Notebook", icon: "location_on", show: sC === "deviceIssues"}, - React.createElement(Select, { - onChange: this._onSetB, values: LOCATIONS, defaultValue: "Anderer Ort", - show: sC === "deviceIssues" - }) - ), - React.createElement( - Input, - { - label: "Ort des Beamer/Fernseher", icon: "location_on", - show: sO === "presentationDeviceIssue" - }, - React.createElement(Select, { - onChange: this._onSetB, values: LOCATIONS_WITH_POSSIBLE_PRESENTATION_DEVICE, - defaultValue: "Anderer Raum", show: sO === "presentationDeviceIssue" - }) - ), - React.createElement( - Input, - {label: "Art des Problems", icon: "bug_report", show: sO === "printerIssue"}, - React.createElement(Select, { - onChange: this._onSetB, - values: ["Papierstau", "Toner leer", "Papier leer", "Drucker bekommt keine Daten"], - defaultValue: "Anderes Problem", show: sO === "subMonitorIssue" - }) - ), - React.createElement( - Input, - {label: "Art des Problems", icon: "bug_report", show: sO === "subMonitorIssue"}, - React.createElement(Select, { - onChange: this._onSetB, - values: ["Schwarzer Bildschirm", "Tage wechseln nicht (Eingefroren)"], - defaultValue: "Anderes Problem", show: sO === "subMonitorIssue" - }) - ), - React.createElement( - Input, - {label: "Art des Problems", icon: "bug_report", show: sO === "wlanIssue"}, - React.createElement(Select, { - onChange: this._onSetB, - values: ["Kein Empfang", "Zugangsdaten funktionieren nicht", "Geschwindigkeit zu langsam"], - defaultValue: "Anderes Problem", show: sO === "wlanIssue" - }) - ), - BASIC_OPTIONS[1].options.map(function (opt) { - if (opt.options) { - return React.createElement( - Input, - { - label: "Art des Problems", icon: "bug_report", - show: sC === "onlineIssues" && sO === opt.id, key: opt.id - }, - React.createElement(Select, { - onChange: that._onSetB, - values: opt.options, - defaultValue: "Anderes Problem", show: sC === "onlineIssues" && sO === opt.id, - key: opt.id - }) - ); - } else { - return React.createElement("p", null); - } - }), - React.createElement( - Input, - { - label: "Handelt es sich um einen Beamer oder einen Fernseher?", icon: "tv", - show: sO === "presentationDeviceIssue" && step === 2 - }, - React.createElement(Select, { - onChange: this._onSetC, values: ["Beamer", "Fernseher/Bildschirm"], - defaultValue: "Sonstiges", show: sO === "presentationDeviceIssue" && step === 2 - }) - ), - React.createElement( - Input, - { - label: "Ort des Druckers", icon: "location_on", - show: sO === "printerIssue" && step === 2 - }, - React.createElement(Select, { - onChange: this._onSetC, values: LOCATIONS, - defaultValue: "Anderer Raum", show: sO === "presentationDeviceIssue" - }) - ), - React.createElement( - Input, - { - label: "Um welches WLAN-Netzwerk handelt es sich?", icon: "wifi", - show: sO === "wlanIssue" && step === 2 - }, - React.createElement(Select, { - onChange: this._onSetC, - values: ["kath-schueler", "kath-lehrer", "kath-edu", "kath-gaeste"], - defaultValue: "-", show: sO === "wlanIssue" && step === 2 - }) - ), - React.createElement( - "div", - { - className: (sC === "deviceIssues" && step === 2 ? "" : "hide ") + "input-field col s12 m12 l4" - }, - React.createElement( - "i", - {className: "material-icons prefix"}, - "device_unknown" - ), - React.createElement("input", { - type: "text", id: "valc", onChange: this._onSetC, - required: sC === "deviceIssues" && step === 2, className: "validate" - }), - React.createElement( - "label", - {htmlFor: "valc"}, - "Um welches Ger\xE4t handelt es sich?" - ) - ), - React.createElement( - "div", - {className: "col s12"}, - React.createElement( - "p", - null, - React.createElement( - "i", - {className: "material-icons left"}, - "info" - ), - this.state.helpText - ) - ) - ), - React.createElement( - "div", - null, - React.createElement("input", { - type: "hidden", name: "a", - value: this.state.selectedOption ? this.state.selectedOption.name : "" - }), - React.createElement("input", {type: "hidden", name: "b", value: this.state.valueB}), - React.createElement("input", {type: "hidden", name: "c", value: this.state.valueC}) - ) - ); - } - }]); - - return REBUSDynSelect; -}(React.Component); - -REBUSDynSelect.propTypes = { - rooms: PropTypes.array.isRequired -}; - -$(document).ready(function () { - var domContainer = document.querySelector('#dynselect'); - ReactDOM.render(React.createElement(REBUSDynSelect, props), domContainer); -});