Skip to content
Snippets Groups Projects
Commit 7dfd0252 authored by Hangzhi Yu's avatar Hangzhi Yu Committed by root
Browse files

Merge branch 'dev-copy' into feature/pwa-optimization

parents 47d1b3f8 21b5ced7
No related branches found
No related tags found
1 merge request!86Merge school-apps
Showing
with 287 additions and 94 deletions
......@@ -5,12 +5,11 @@ venv/
secure*
*.aux
*.log
class.pdf
class.tex
aktuell.pdf
aktuell.tex
.idea/
media/
node_modules/
latex/
staticcollect/
.idea
dynselect2/src/*
......
......@@ -10,7 +10,7 @@ sudo apt install python3 python3-dev python3-pip git mariadb-server python3-venv
```
### MySQL-Datenbank
1. Datenbank `schoolapps` (`utf8_general_ci`) anlegen
1. Datenbanken `schoolapps` und `Untis` (`utf8_general_ci`) anlegen
2. Benutzer `www-data` anlegen
3. Benutzer `www-data` alle Rechte auf `schoolapps` geben
4. Benutzer `untis-read` anlegen
......
......@@ -7,7 +7,7 @@ import PropTypes from "prop-types";
const OPTIONS_ONLINE_COMMON = [
"Portal ist nicht erreichbar",
"Fehlermeldung(en) tauchen auf",
"Anmeldung funktiontiert nicht",
"Anmeldung funktioniert nicht",
"Zugangsdaten vergessen"
];
......@@ -21,6 +21,11 @@ const BASIC_OPTIONS = [
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",
......@@ -142,6 +147,10 @@ const BASIC_OPTIONS = [
{
id: "missingKeys",
name: "Fehlende Tasten auf der Tastatur"
},
{
id: "hardwareMisc",
name: "Andere Hardware defekt / Äußere Schäden"
}
......@@ -322,7 +331,7 @@ class App extends Component {
className="input-field col s12 m12 l4">
<i className={"material-icons prefix"}>list</i>
<select onChange={this._onCategoryChanges} defaultValue={"noCategory"} className={"validate"}
required={true}>
required={true}>-
<option value={"noCategory"} disabled={true}>Keine Kategorie ausgewählt</option>
{BASIC_OPTIONS.map(function (category) {
return <optgroup label={category.name} key={category.id}>
......@@ -349,11 +358,18 @@ class App extends Component {
defaultValue={"Anderer Raum"} show={sO === "presentationDeviceIssue"}/>
</Input>
{/* Section B – Printer Issue */}
<Input label={"Art des Problems"} icon={"bug_report"} show={sO === "printerIssue"}>
<Select onChange={this._onSetB}
values={["Papierstau", "Toner leer", "Papier leer", "Drucker bekommt keine Daten"]}
defaultValue={"Anderes Problem"} show={sO === "subMonitorIssue"}/>
</Input>
{/* Section B – Substitution Monitor Issue */}
<Input label={"Art des Problems"} icon={"bug_report"} show={sO === "subMonitorIssue"}>
<Select onChange={this._onSetB}
values={["Schwarzer Bildschirm", "Tage wechseln nicht (Eingefroren)"]}
defaultValue={"Anderer Raum"} show={sO === "subMonitorIssue"}/>
defaultValue={"Anderes Problem"} show={sO === "subMonitorIssue"}/>
</Input>
{/* Section B – WLAN Issue */}
......@@ -386,6 +402,13 @@ class App extends Component {
defaultValue={"Sonstiges"} show={sO === "presentationDeviceIssue" && step === 2}/>
</Input>
{/* Section C – Presentation Device Issues */}
<Input label={"Ort des Druckers"} icon={"location_on"}
show={sO === "printerIssue" && step === 2}>
<Select onChange={this._onSetC} values={LOCATIONS}
defaultValue={"Anderer Raum"} show={sO === "presentationDeviceIssue"}/>
</Input>
{/* Section C – WLAN Issue */}
<Input label={"Um welches WLAN-Netzwerk handelt es sich?"} icon={"wifi"}
show={sO === "wlanIssue" && step === 2}>
......
......@@ -2,8 +2,4 @@ import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
ReactDOM.render( < App
rooms = {["A", "B"
]
}
/>, document.getElementById('root'));
ReactDOM.render(<App rooms={["A", "B"]}/>, document.getElementById('root'));
import React, {Component} from 'react';
// import "materialize-css/dist/css/materialize.css";
//import "materialize-css/dist/css/materialize.css";
import M from "materialize-css/dist/js/materialize";
import PropTypes from "prop-types";
......@@ -7,7 +7,7 @@ import PropTypes from "prop-types";
const OPTIONS_ONLINE_COMMON = [
"Portal ist nicht erreichbar",
"Fehlermeldung(en) tauchen auf",
"Anmeldung funktiontiert nicht",
"Anmeldung funktioniert nicht",
"Zugangsdaten vergessen"
];
......@@ -21,6 +21,11 @@ const BASIC_OPTIONS = [
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",
......@@ -142,6 +147,10 @@ const BASIC_OPTIONS = [
{
id: "missingKeys",
name: "Fehlende Tasten auf der Tastatur"
},
{
id: "hardwareMisc",
name: "Andere Hardware defekt / Äußere Schäden"
}
......@@ -322,7 +331,7 @@ class App extends Component {
className="input-field col s12 m12 l4">
<i className={"material-icons prefix"}>list</i>
<select onChange={this._onCategoryChanges} defaultValue={"noCategory"} className={"validate"}
required={true}>
required={true}>-
<option value={"noCategory"} disabled={true}>Keine Kategorie ausgewählt</option>
{BASIC_OPTIONS.map(function (category) {
return <optgroup label={category.name} key={category.id}>
......@@ -349,11 +358,18 @@ class App extends Component {
defaultValue={"Anderer Raum"} show={sO === "presentationDeviceIssue"}/>
</Input>
{/* Section B – Printer Issue */}
<Input label={"Art des Problems"} icon={"bug_report"} show={sO === "printerIssue"}>
<Select onChange={this._onSetB}
values={["Papierstau", "Toner leer", "Papier leer", "Drucker bekommt keine Daten"]}
defaultValue={"Anderes Problem"} show={sO === "subMonitorIssue"}/>
</Input>
{/* Section B – Substitution Monitor Issue */}
<Input label={"Art des Problems"} icon={"bug_report"} show={sO === "subMonitorIssue"}>
<Select onChange={this._onSetB}
values={["Schwarzer Bildschirm", "Tage wechseln nicht (Eingefroren)"]}
defaultValue={"Anderer Raum"} show={sO === "subMonitorIssue"}/>
defaultValue={"Anderes Problem"} show={sO === "subMonitorIssue"}/>
</Input>
{/* Section B – WLAN Issue */}
......@@ -386,6 +402,13 @@ class App extends Component {
defaultValue={"Sonstiges"} show={sO === "presentationDeviceIssue" && step === 2}/>
</Input>
{/* Section C – Presentation Device Issues */}
<Input label={"Ort des Druckers"} icon={"location_on"}
show={sO === "printerIssue" && step === 2}>
<Select onChange={this._onSetC} values={LOCATIONS}
defaultValue={"Anderer Raum"} show={sO === "presentationDeviceIssue"}/>
</Input>
{/* Section C – WLAN Issue */}
<Input label={"Um welches WLAN-Netzwerk handelt es sich?"} icon={"wifi"}
show={sO === "wlanIssue" && step === 2}>
......
......@@ -3,18 +3,51 @@
<main>
<script>
function setTime(lesson_field) {
// fill timefield based on lesson value
if (lesson_field.id === 'id_from_lesson') {
$('[id=id_from_time]').val(lesson_field.value);
} else {
// calculate lessons end time
// string methods easier than date function muddle
var h = lesson_field.value.split(':')[0];
var m = lesson_field.value.split(':')[1];
if (m < 15) {
m = parseInt(m) + 45;
} else {
m = parseInt(m) - 15;
h = parseInt(h) + 1;
}
m = m.toString();
h = h.toString();
if (m.length === 1) {
m = '0' + m
}
var newTime = h + ':' + m;
$('[id=id_to_time]').val(newTime);
}
}
</script>
<h4>Antrag auf Unterrichtsbefreiung</h4>
<form method = "POST" >
<form method="POST">
{% csrf_token %}
{# Von#}
{# <input type="text" label="Von" input_formats=['%d.%m.%Y'] value="{{ from_dt }}" name="from_date" >#}
{# Von#}
{# <input type="text" label="Von" input_formats=['%d.%m.%Y'] value="{{ from_dt }}" name="from_date" >#}
{% form form=form %}
{% endform %}
<button type="submit" class="waves-effect waves-light btn green">
<i class="material-icons left">send</i> Antrag stellen
</button>
</form>
<script>
$("#id_from_date").change(function () {
$("#id_to_date").val($("#id_from_date").val());
$("#id_to_date").change();
})
</script>
</main>
{% include 'partials/footer.html' %}
......@@ -142,7 +142,7 @@ def check1(request):
link=request.build_absolute_uri(reverse('aub_details', args=[aub.id]))
)
aub_list = Aub.objects.filter(status=0).order_by('created_at')
aub_list = Aub.objects.filter(status=0).order_by('from_date')
aubs = AUBFilter(request.GET, queryset=aub_list)
return render(request, 'aub/check.html', {'filter': aubs})
......@@ -186,7 +186,7 @@ def check2(request):
link=request.build_absolute_uri(reverse('aub_details', args=[aub.id]))
)
aub_list = Aub.objects.filter(status=1).order_by('created_at')
aub_list = Aub.objects.filter(status=1).order_by('from_date')
aubs = AUBFilter(request.GET, queryset=aub_list)
return render(request, 'aub/check.html', {'filter': aubs})
......
from django.contrib.auth.decorators import login_required
from django.shortcuts import render, redirect
from django.urls import reverse
from django.http import HttpResponseNotFound
from .models import Activity, register_notification
# from .apps import DashboardConfig
from mailer import send_mail_with_template
......
# Generated by Django 2.2.1 on 2019-08-18 07:10
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('debug', '0002_auto_20190523_1627'),
]
operations = [
migrations.AlterField(
model_name='debuglog',
name='filename',
field=models.FilePathField(blank=True, match='.*.log', path='/home/p-h/git/school-apps/schoolapps/latex', verbose_name='Dateiname zur Logdatei (falls nicht Log-Text)'),
),
]
# Generated by Django 2.2.4 on 2019-09-16 12:50
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('debug', '0003_auto_20190818_0910'),
]
operations = [
migrations.AlterField(
model_name='debuglog',
name='filename',
field=models.FilePathField(blank=True, match='.*.log', path='/data/Silas/Daten/school-apps/schoolapps/latex', verbose_name='Dateiname zur Logdatei (falls nicht Log-Text)'),
),
]
......@@ -10,35 +10,43 @@
<ul class="collapsible">
{% for question in section.questions.all %}
{% if question.show %}
<li>
<div class="collapsible-header flow-text">
<i class="material-icons">
{% if question.icon %}
{{ question.icon }}
{% else %}
question_answer
{% endif %}
</i>
{{ question.question_text }}
</div>
<div class="collapsible-body">
{{ question.answer_text|safe }}
</div>
</li>
<li>
<div class="collapsible-header flow-text">
<i class="material-icons">
{% if question.icon %}
{{ question.icon }}
{% else %}
question_answer
{% endif %}
</i>
{{ question.question_text }}
</div>
<div class="collapsible-body">
{{ question.answer_text|safe }}
</div>
</li>
{% endif %}
{% endfor %}
</ul>
</section>
{% endfor %}
<p class="flow-text">
Deine Frage war nicht dabei?
</p>
<p>
<a class="btn blue waves-effect waves-green" href="{% url "ask-faq" %}">
<i class="material-icons left">chat</i>
Deine Frage stellen
</a>
{% if user.is_authenticated %}
<a class="btn blue waves-effect waves-green" href="{% url "ask-faq" %}">
<i class="material-icons left">chat</i>
Deine Frage stellen
</a>
{% else %}
Schreibe uns an
<a href="mailto:support@katharineum.de">support@katharineum.de</a> und wir versuchen, deine Frage zu
beantworten.
{% endif %}
</p>
</main>
{% include 'partials/footer.html' %}
......@@ -4,4 +4,4 @@ from . import views
urlpatterns = [
path('', views.faq, name='faq'),
path('ask', views.ask, name='ask-faq')
]
\ No newline at end of file
]
from django.shortcuts import render
from django.shortcuts import render, redirect
from django.contrib.auth.decorators import login_required
from faq.models import FAQSection, FAQQuestion, Question
from faq.forms import FAQForm
......@@ -20,6 +21,7 @@ def faq(request):
}
return render(request, 'faq/faq.html', context)
@login_required
def ask(request):
if request.method == 'POST':
form = FAQForm(request.POST)
......@@ -40,4 +42,4 @@ def ask(request):
else:
form = FAQForm()
return render(request, "faq/ask.html", {"form": form})
\ No newline at end of file
return render(request, "faq/ask.html", {"form": form})
......@@ -4,7 +4,7 @@ from django.template.loader import render_to_string
SENDER_EMAIL = 'SchoolApps <infoplan@katharineum.de>'
def send_mail_with_template(title, receivers, plain_template, html_template, context={}):
def send_mail_with_template(title, receivers, plain_template, html_template, context={}, sender_email=SENDER_EMAIL):
msg_plain = render_to_string(plain_template, context)
msg_html = render_to_string(html_template, context)
......@@ -12,7 +12,7 @@ def send_mail_with_template(title, receivers, plain_template, html_template, con
send_mail(
title,
msg_plain,
SENDER_EMAIL,
sender_email,
receivers,
html_message=msg_html,
)
......
import datetime
import os
import time
from django.contrib.auth.decorators import login_required, permission_required
from django.http import FileResponse
......@@ -66,6 +67,9 @@ def show_current(request):
if days_to_add < 0:
days_to_add = days_to_add + 7
if days_to_add == 6 or days_to_add == 7:
calendar_week += 1
# Create datetime with next friday and time 14:10
friday = current_date + datetime.timedelta(days=days_to_add)
friday_14_10 = timezone.datetime(friday.year, friday.month, friday.day, 14, 10)
......
......@@ -123,7 +123,7 @@ EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
# TIMETABLE
TIMETABLE_WIDTH = 5
TIMETABLE_HEIGHT = 10
TIMETABLE_HEIGHT = 9
LESSONS = [('8:00', '1.'), ('8:45', '2.'), ('9:45', '3.'), ('10:35', '4.'), ('11:35', '5.'),
('12:25', '6.'), ('13:15', '7.'), ('14:05', '8.'), ('14:50', '9.')]
SHORT_WEEK_DAYS = ["Mo", "Di", "Mi", "Do", "Fr"]
......
......@@ -21,6 +21,7 @@ from django.contrib.staticfiles.views import serve
from django.urls import path
from django.conf.urls.static import static
from django.conf import settings
from django.views import defaults
from schoolapps.settings import BASE_DIR
......@@ -28,6 +29,7 @@ from schoolapps.settings import BASE_DIR
def manifest(request):
return serve(request, "manifest.json")
urlpatterns = [
#############
# Dashboard #
......@@ -74,9 +76,13 @@ urlpatterns = [
path('', include('pwa.urls')),
path('martor/', include('martor.urls')),
#######
# 404 #
#######
path('404/', custom_page_not_found, name='404'),
]
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
# handler404 = 'dashboard.views.error_404'
......@@ -25,38 +25,15 @@ function getNowFormatted() {
}
function setTime(lesson_field) {
// fill timefield based on lesson value
if (lesson_field.id === 'id_from_lesson') {
$('[id=id_from_time]').val(lesson_field.value);
} else {
// calculate lessons end time
// string methods easier than date function muddle
var h = lesson_field.value.split(':')[0];
var m = lesson_field.value.split(':')[1];
if (m < 15) {
m = parseInt(m) + 45;
} else {
m = parseInt(m) - 15;
h = parseInt(h) + 1;
}
m = m.toString()
h = h.toString()
if (m.length === 1) {
m = '0' + m
}
var newTime = h + ':' + m;
$('[id=id_to_time]').val(newTime);
}
}
function selectActiveLink() {
var currlocation = $('meta[name="active-loaction"]');
var url_name = currlocation.attr("content");
//console.log(url_name);
$("#" + url_name).addClass("active");
$("#" + url_name).parent().parent().parent().addClass("active");
var selector = ".url-" + url_name;
console.log(selector);
$(selector).addClass("active");
$(selector).parent().parent().parent().addClass("active");
}
$(document).ready(function () {
......@@ -82,7 +59,7 @@ $(document).ready(function () {
// Buttons
today: 'Heute',
clear: 'Löschen',
cancel: 'Abbrechen',
done: 'OK',
},
......@@ -95,9 +72,11 @@ $(document).ready(function () {
$('.timepicker').timepicker({
twelveHour: false,
autoClose: true,
cancelText: 'Abbrechen',
clearText: 'Löschen',
doneText: 'OK'
i18n: {
cancel: 'Abbrechen',
clear: 'Löschen',
done: 'OK'
},
});
// Initialize tooltip [MAT]
......
......@@ -66,10 +66,51 @@ header a.sidenav-trigger {
z-index: 2;
}
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;
......@@ -118,10 +159,12 @@ span.badge .material-icons {
.smart-plan-badge {
margin: 5px 20px 5px 0;
}
li.active > a > .sidenav-badge{
li.active > a > .sidenav-badge {
background-color: whitesmoke !important;
color: #DA3D56 !important;
}
.timetable-plan .row, .timetable-plan .col {
display: flex;
padding: 0 .25rem;
......@@ -232,19 +275,33 @@ table.substitutions td, table.substitutions th {
.btn-timetable-quicklaunch {
margin: 1%;
width: 30%;
background-color: rgba(0,0,0,0.05) !important;
background-color: rgba(0, 0, 0, 0.05) !important;
color: black;
}
.btn-timetable-quicklaunch:hover{
.btn-timetable-quicklaunch:hover {
background-color: #da1f3d !important;
color: whitesmoke;
}
.no-margin {
margin: 0 !important;
margin-left: 0 !important;
margin-right: 0 !important;
margin-top: 0 !important;
margin-bottom: 0 !important;
}
.valign-middle {
vertical-align: middle;
}
.valign-top {
vertical-align: top;
}
.valign-bot {
vertical-align: bottom;
}
.height-inherit {
height: 100%;
}
/* Table*/
......@@ -260,6 +317,10 @@ table.striped > tbody > tr:nth-child(odd) {
display: none;
}
.print-icon {
margin-top: 1.52rem;
}
@media print {
body {
font-size: 15px;
......@@ -450,29 +511,35 @@ i.collapsible-trigger {
background-color: rgba(218, 31, 61, 0.65);
}
.no-margin{
.no-margin {
margin: 0 !important;
}
.no-pad-left{
.no-pad-left {
padding-left: 0 !important;
}
.no-pad-right{
.no-pad-right {
padding-right: 0 !important;
}
.sidenav a:not(.collapsible-header){
.sidenav a:not(.collapsible-header) {
padding: 0 16px;
}
.waves-effect.waves-primary .waves-ripple {
/* The alpha value allows the text and background color
of the button to still show through. */
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{
}
.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;
}
......@@ -488,3 +555,19 @@ i.collapsible-trigger {
/*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;
}
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment