Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6b197fd9d1 | |||
| 58064ee249 | |||
| f7573b9a62 | |||
| 85d758fadb | |||
| 212dd2abcf |
+1
-1
@@ -1,7 +1,7 @@
|
||||
NUITKA_BUILD=0
|
||||
INVENTAR_HTTP_PORT=10000
|
||||
INVENTAR_HTTP_PORTS=10000
|
||||
INVENTAR_APP_IMAGE=ghcr.io/aiirondev/legendary-octo-garbanzo:v0.7.39
|
||||
INVENTAR_APP_IMAGE=ghcr.io/aiirondev/legendary-octo-garbanzo:v0.7.42
|
||||
INVENTAR_APP_CPUS=1.0
|
||||
INVENTAR_APP_MEM_LIMIT=384m
|
||||
INVENTAR_APP_MEM_SWAP_LIMIT=768m
|
||||
|
||||
+24
-1
@@ -25,9 +25,10 @@ Features:
|
||||
- Booking and reservation of items
|
||||
"""
|
||||
|
||||
from flask import Flask, render_template, request, redirect, url_for, session, flash, send_from_directory, get_flashed_messages, jsonify, Response, make_response, send_file
|
||||
from flask import Flask, render_template, request, redirect, url_for, session, flash, send_from_directory, get_flashed_messages, jsonify, Response, make_response, send_file, abort
|
||||
from werkzeug.utils import secure_filename
|
||||
from werkzeug.middleware.proxy_fix import ProxyFix
|
||||
from jinja2 import TemplateNotFound
|
||||
import user as us
|
||||
import items as it
|
||||
import ausleihung as au
|
||||
@@ -412,6 +413,26 @@ def _set_security_headers(response):
|
||||
return response
|
||||
|
||||
|
||||
@app.errorhandler(TemplateNotFound)
|
||||
def handle_template_not_found(e):
|
||||
"""Handle missing template files with a 404 response."""
|
||||
app.logger.error(f"Template not found: {e.name}")
|
||||
if request.is_json or request.path.startswith('/api/'):
|
||||
return jsonify({'error': 'Template not found', 'status': 404}), 404
|
||||
return abort(404)
|
||||
|
||||
|
||||
@app.errorhandler(404)
|
||||
def handle_not_found(e):
|
||||
"""Handle 404 errors with a user-friendly response."""
|
||||
app.logger.warning(f"404 Not Found: {request.path}")
|
||||
if request.is_json or request.path.startswith('/api/'):
|
||||
return jsonify({'error': 'Not found', 'status': 404}), 404
|
||||
if 'username' in session:
|
||||
return render_template('error.html', error_code=404, error_message='Seite nicht gefunden.'), 404
|
||||
return redirect(url_for('login'))
|
||||
|
||||
|
||||
def _csrf_error_response(message='CSRF token fehlt oder ist ungültig.'):
|
||||
if request.is_json or request.path.startswith('/api/') or request.path in {'/download_book_cover', '/proxy_image', '/log_mobile_issue'}:
|
||||
return jsonify({'error': message}), 400
|
||||
@@ -8566,11 +8587,13 @@ def manage_filters():
|
||||
# Get predefined filter values
|
||||
filter1_values = it.get_predefined_filter_values(1)
|
||||
filter2_values = it.get_predefined_filter_values(2)
|
||||
filter3_values = it.get_predefined_filter_values(3)
|
||||
|
||||
return render_template(
|
||||
'manage_filters.html',
|
||||
filter1_values=filter1_values,
|
||||
filter2_values=filter2_values,
|
||||
filter3_values=filter3_values,
|
||||
library_module_enabled=cfg.MODULES.is_enabled('library'),
|
||||
student_cards_module_enabled=cfg.MODULES.is_enabled('student_cards')
|
||||
)
|
||||
|
||||
+12
-3
@@ -570,7 +570,10 @@ def get_primary_filters():
|
||||
items = db['items']
|
||||
filters = [f for f in items.distinct('Filter', _active_record_query(_non_library_query())) if f]
|
||||
client.close()
|
||||
return filters
|
||||
|
||||
# Add predefined values
|
||||
predefined = get_predefined_filter_values(1)
|
||||
return sorted(list(set(filters + predefined)))
|
||||
except Exception as e:
|
||||
print(f"Error retrieving primary filters: {e}")
|
||||
return []
|
||||
@@ -589,7 +592,10 @@ def get_secondary_filters():
|
||||
items = db['items']
|
||||
filters = [f for f in items.distinct('Filter2', _active_record_query(_non_library_query())) if f]
|
||||
client.close()
|
||||
return filters
|
||||
|
||||
# Add predefined values
|
||||
predefined = get_predefined_filter_values(2)
|
||||
return sorted(list(set(filters + predefined)))
|
||||
except Exception as e:
|
||||
print(f"Error retrieving secondary filters: {e}")
|
||||
return []
|
||||
@@ -608,7 +614,10 @@ def get_tertiary_filters():
|
||||
items = db['items']
|
||||
filters = [f for f in items.distinct('Filter3', _active_record_query(_non_library_query())) if f]
|
||||
client.close()
|
||||
return filters
|
||||
|
||||
# Add predefined values
|
||||
predefined = get_predefined_filter_values(3)
|
||||
return sorted(list(set(filters + predefined)))
|
||||
except Exception as e:
|
||||
print(f"Error retrieving tertiary filters: {e}")
|
||||
return []
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}
|
||||
{% if error_code == 404 %}
|
||||
Seite nicht gefunden - Inventarsystem
|
||||
{% else %}
|
||||
Fehler - Inventarsystem
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="error-container" style="text-align: center; padding: 60px 20px; min-height: 70vh; display: flex; flex-direction: column; justify-content: center; align-items: center;">
|
||||
<div style="max-width: 600px;">
|
||||
<!-- Error Code Display -->
|
||||
<div style="font-size: 120px; font-weight: bold; color: #ef4444; margin-bottom: 20px;">
|
||||
{{ error_code }}
|
||||
</div>
|
||||
|
||||
<!-- Error Title -->
|
||||
<h1 style="font-size: 32px; margin: 20px 0; color: #1f2937;">
|
||||
{% if error_code == 404 %}
|
||||
Seite nicht gefunden
|
||||
{% else %}
|
||||
Ein Fehler ist aufgetreten
|
||||
{% endif %}
|
||||
</h1>
|
||||
|
||||
<!-- Error Message -->
|
||||
<p style="font-size: 18px; color: #6b7280; margin: 20px 0 40px;">
|
||||
{{ error_message or 'Es tut uns leid, aber die angeforderte Seite konnte nicht gefunden werden.' }}
|
||||
</p>
|
||||
|
||||
<!-- Action Buttons -->
|
||||
<div style="display: flex; gap: 15px; justify-content: center; flex-wrap: wrap;">
|
||||
<a href="{{ url_for('home') }}" class="button" style="background-color: #3b82f6; color: white; padding: 12px 30px; text-decoration: none; border-radius: 5px; display: inline-block; font-weight: 500;">
|
||||
Zur Startseite
|
||||
</a>
|
||||
<a href="javascript:history.back()" class="button" style="background-color: #6b7280; color: white; padding: 12px 30px; text-decoration: none; border-radius: 5px; display: inline-block; font-weight: 500;">
|
||||
Zurück
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- Additional Help -->
|
||||
<div style="margin-top: 60px; padding: 20px; background-color: #f3f4f6; border-radius: 8px;">
|
||||
<p style="color: #6b7280; font-size: 14px;">
|
||||
Wenn Sie denken, dass dies ein Fehler ist, oder Sie Hilfe benötigen,
|
||||
<a href="{{ url_for('impressum') }}" style="color: #3b82f6; text-decoration: none;">kontaktieren Sie den Administrator</a>.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.error-container {
|
||||
animation: fadeIn 0.3s ease-in;
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(10px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
.button:hover {
|
||||
opacity: 0.9;
|
||||
transform: translateY(-2px);
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
@@ -15,16 +15,16 @@
|
||||
<h1 class="mb-4">Filterwerte verwalten</h1>
|
||||
|
||||
<div class="row">
|
||||
<!-- Filter 1: Unterrichtsfach -->
|
||||
<div class="col-md-6">
|
||||
<!-- Filter 1 -->
|
||||
<div class="col-md-4">
|
||||
<div class="card mb-4">
|
||||
<div class="card-header">
|
||||
<h2 class="card-title h5 mb-0">Unterrichtsfach (Filter 1)</h2>
|
||||
<h2 class="card-title h5 mb-0">Fach/Kategorie (Filter 1)</h2>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form method="POST" action="{{ url_for('add_filter_value', filter_num=1) }}" class="mb-4">
|
||||
<div class="input-group">
|
||||
<input type="text" name="value" class="form-control" placeholder="Neues Unterrichtsfach..." required>
|
||||
<input type="text" name="value" class="form-control" placeholder="Neuer Wert..." required>
|
||||
<button type="submit" class="btn btn-primary">Hinzufügen</button>
|
||||
</div>
|
||||
</form>
|
||||
@@ -51,16 +51,16 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Filter 2: Jahrgangsstufe -->
|
||||
<div class="col-md-6">
|
||||
<!-- Filter 2 -->
|
||||
<div class="col-md-4">
|
||||
<div class="card mb-4">
|
||||
<div class="card-header">
|
||||
<h2 class="card-title h5 mb-0">Jahrgangsstufe (Filter 2)</h2>
|
||||
<h2 class="card-title h5 mb-0">System/Bereich (Filter 2)</h2>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form method="POST" action="{{ url_for('add_filter_value', filter_num=2) }}" class="mb-4">
|
||||
<div class="input-group">
|
||||
<input type="text" name="value" class="form-control" placeholder="Neue Jahrgangsstufe..." required>
|
||||
<input type="text" name="value" class="form-control" placeholder="Neuer Wert..." required>
|
||||
<button type="submit" class="btn btn-primary">Hinzufügen</button>
|
||||
</div>
|
||||
</form>
|
||||
@@ -86,6 +86,42 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Filter 3 -->
|
||||
<div class="col-md-4">
|
||||
<div class="card mb-4">
|
||||
<div class="card-header">
|
||||
<h2 class="card-title h5 mb-0">Typ/Art (Filter 3)</h2>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form method="POST" action="{{ url_for('add_filter_value', filter_num=3) }}" class="mb-4">
|
||||
<div class="input-group">
|
||||
<input type="text" name="value" class="form-control" placeholder="Neuer Wert..." required>
|
||||
<button type="submit" class="btn btn-primary">Hinzufügen</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<h5 class="mb-3">Vorhandene Werte</h5>
|
||||
{% if filter3_values %}
|
||||
<div class="list-group">
|
||||
{% for value in filter3_values %}
|
||||
<div class="list-group-item d-flex justify-content-between align-items-center">
|
||||
{{ value }}
|
||||
<form method="POST" action="{{ url_for('remove_filter_value', filter_num=3, value=value) }}" class="d-inline">
|
||||
<button type="submit" class="btn btn-sm btn-danger"
|
||||
onclick="return confirm('Sind Sie sicher, dass Sie den Wert \"' + '{{ value }}'.replace(/'/g, '\\\'') + '\" löschen möchten?');">
|
||||
Entfernen
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="alert alert-info">Keine Werte definiert.</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="alert alert-warning">
|
||||
|
||||
@@ -709,7 +709,6 @@
|
||||
</style>
|
||||
|
||||
<div class="upload-container">
|
||||
<a href="{{ url_for(back_target|default('home_admin')) }}" class="nav-back-button">← Zurück zur Artikelübersicht</a>
|
||||
|
||||
{% if show_library_features %}
|
||||
<div style="border:1px solid #dbe4ee; border-radius:8px; padding:14px; margin-bottom:16px; background:#f8fbff;">
|
||||
|
||||
+1
-7
@@ -498,8 +498,6 @@ def check_nm_pwd(username, password):
|
||||
finally:
|
||||
client.close()
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def add_user(
|
||||
username,
|
||||
@@ -536,16 +534,12 @@ def add_user(
|
||||
for key, value in page_permissions.items():
|
||||
permission_defaults['pages'][str(key)] = bool(value)
|
||||
|
||||
alias_first = name if str(name or '').strip() else username
|
||||
alias_last = last_name if str(last_name or '').strip() else ''
|
||||
name_alias = build_name_synonym(alias_first, alias_last)
|
||||
|
||||
user_doc = {
|
||||
'Username': username,
|
||||
'Password': hashing(password),
|
||||
'Admin': False,
|
||||
'active_ausleihung': None,
|
||||
'name': name_alias,
|
||||
'name': name.strip() if name else '',
|
||||
'last_name': last_name.strip() if last_name else '',
|
||||
'IsStudent': bool(is_student),
|
||||
'PermissionPreset': permission_defaults['preset'],
|
||||
|
||||
Reference in New Issue
Block a user