The School year rollover button is placed in the school settings.
Release Inventarsystem / release-docker (push) Successful in 2m16s
Release Inventarsystem / release-docker (push) Successful in 2m16s
This commit is contained in:
-63
@@ -228,7 +228,6 @@ def rollover_student_card_classes(dry_run=False, *, max_class=None, graduate_lab
|
||||
client.close()
|
||||
|
||||
|
||||
# Admin route to trigger rollover manually
|
||||
@app.route('/admin/trigger_school_year_rollover', methods=['POST'])
|
||||
def admin_trigger_school_year_rollover():
|
||||
if 'username' not in session:
|
||||
@@ -3038,42 +3037,6 @@ def optimized_image(filename):
|
||||
app.logger.error(f"Error serving optimized image {filename}: {str(e)}")
|
||||
return Response("Optimized image not found", status=404)
|
||||
|
||||
|
||||
# @app.route('/QRCodes/<filename>')
|
||||
# def qrcode_file(filename):
|
||||
# """
|
||||
# Serve QR code files from the QRCodes directory.
|
||||
#
|
||||
# Args:
|
||||
# filename (str): Name of the QR code file to serve
|
||||
#
|
||||
# Returns:
|
||||
# flask.Response: The requested QR code file or placeholder image if not found
|
||||
# """
|
||||
# try:
|
||||
# # Check production path first
|
||||
# prod_path = "/var/Inventarsystem/Web/QRCodes"
|
||||
# dev_path = app.config['QR_CODE_FOLDER']
|
||||
# if os.path.exists(os.path.join(prod_path, filename)):
|
||||
# return send_from_directory(prod_path, filename)
|
||||
# if os.path.exists(os.path.join(dev_path, filename)):
|
||||
# return send_from_directory(dev_path, filename)
|
||||
#
|
||||
# # Use a placeholder image if file not found - first try SVG, then PNG
|
||||
# svg_placeholder_path = os.path.join(app.static_folder, 'img', 'no-image.svg')
|
||||
# png_placeholder_path = os.path.join(app.static_folder, 'img', 'no-image.png')
|
||||
#
|
||||
# if os.path.exists(svg_placeholder_path):
|
||||
# return send_from_directory(app.static_folder, 'img/no-image.svg')
|
||||
# elif os.path.exists(png_placeholder_path):
|
||||
# return send_from_directory(app.static_folder, 'img/no-image.png')
|
||||
# else:
|
||||
# return send_from_directory(app.static_folder, 'favicon.ico')
|
||||
# except Exception as e:
|
||||
# print(f"Error serving QR code {filename}: {str(e)}")
|
||||
# return Response("QR code not found", status=404)
|
||||
|
||||
|
||||
@app.route('/<path:filename>')
|
||||
def catch_all_files(filename):
|
||||
"""
|
||||
@@ -3136,32 +3099,6 @@ def test_connection():
|
||||
"""
|
||||
return {'status': 'success', 'message': 'Connection successful', 'status_code': 200}
|
||||
|
||||
""" if sucess in deployment the funktion can be removed
|
||||
@app.route('/user_status')
|
||||
def user_status():
|
||||
|
||||
API endpoint to get the current user's status (username, admin status).
|
||||
Used by JavaScript in templates to personalize the UI.
|
||||
|
||||
Returns:
|
||||
JSON: User status information or error if not authenticated
|
||||
|
||||
if 'username' in session:
|
||||
is_admin = us.check_admin(session['username'])
|
||||
return jsonify({
|
||||
'authenticated': True,
|
||||
'username': session['username'],
|
||||
'is_admin': is_admin
|
||||
})
|
||||
else:
|
||||
return jsonify({
|
||||
'authenticated': False,
|
||||
'error': 'Not logged in'
|
||||
}), 401
|
||||
"""
|
||||
|
||||
|
||||
##################################################### changes to be made to account for the new account permison managment system ##############################
|
||||
|
||||
@app.route('/')
|
||||
def home():
|
||||
|
||||
@@ -120,9 +120,64 @@
|
||||
<p>Diese Angaben erscheinen künftig im amtlichen Audit-PDF und in anderen Behördenberichten.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Danger Zone: Schuljahreswechsel -->
|
||||
<div class="card danger-zone" style="grid-column: 1 / -1; border-color: #fca5a5;">
|
||||
<div class="card-header" style="background: #fef2f2; border-bottom: 1px solid #fca5a5;">
|
||||
<h2 style="color: #991b1b;">Erweiterte Aktionen</h2>
|
||||
</div>
|
||||
<div class="card-body" style="display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 15px;">
|
||||
<div>
|
||||
<strong style="color: #7f1d1d; display: block; font-size: 1.05rem; margin-bottom: 4px;">Schuljahreswechsel durchführen</strong>
|
||||
<span style="color: #991b1b; font-size: 0.9rem;">Diese Aktion bereitet das System auf das neue Schuljahr vor (z. B. Hochstufen von Klassen).</span>
|
||||
</div>
|
||||
<button type="button"
|
||||
id="btn-rollover"
|
||||
class="btn btn-danger"
|
||||
onclick="triggerSchoolYearRollover()">
|
||||
Schuljahreswechsel auslösen
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
async function triggerSchoolYearRollover() {
|
||||
if (!confirm('Möchtest du den Schuljahreswechsel wirklich durchführen? Dies kann nicht rückgängig gemacht werden!')) {
|
||||
return;
|
||||
}
|
||||
|
||||
const btn = document.getElementById('btn-rollover');
|
||||
btn.disabled = true;
|
||||
btn.textContent = 'Wird ausgeführt...';
|
||||
|
||||
try {
|
||||
const response = await fetch('/admin/trigger_school_year_rollover', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (response.ok && data.ok) {
|
||||
alert('Schuljahreswechsel erfolgreich durchgeführt!\n\nZusammenfassung:\n' + JSON.stringify(data.summary, null, 2));
|
||||
location.reload();
|
||||
} else {
|
||||
alert('Fehler: ' + (data.message || 'Schuljahreswechsel konnte nicht durchgeführt werden.'));
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Rollover error:', error);
|
||||
alert('Netzwerk- oder Serverfehler beim Ausführen des Schuljahreswechsels.');
|
||||
} finally {
|
||||
btn.disabled = false;
|
||||
btn.textContent = 'Schuljahreswechsel auslösen';
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.container {
|
||||
max-width: 1100px;
|
||||
@@ -245,12 +300,17 @@
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.btn:disabled {
|
||||
opacity: 0.6;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background: #2563eb;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
.btn-primary:hover:not(:disabled) {
|
||||
background: #1d4ed8;
|
||||
color: #fff;
|
||||
}
|
||||
@@ -261,11 +321,21 @@
|
||||
border-color: #d1d5db;
|
||||
}
|
||||
|
||||
.btn-secondary:hover {
|
||||
.btn-secondary:hover:not(:disabled) {
|
||||
background: #e5e7eb;
|
||||
color: #111827;
|
||||
}
|
||||
|
||||
.btn-danger {
|
||||
background: #ef4444;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.btn-danger:hover:not(:disabled) {
|
||||
background: #dc2626;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.preview-card p {
|
||||
margin: 0 0 10px;
|
||||
line-height: 1.45;
|
||||
@@ -283,5 +353,15 @@
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
.danger-zone .card-body {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
}
|
||||
.danger-zone .btn {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user