Compare commits

...

4 Commits

4 changed files with 62 additions and 9 deletions
+43 -2
View File
@@ -657,7 +657,28 @@ def _save_school_logo_upload(upload_file, tenant_id=None, tenant_db=None):
os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True)
upload_file.save(logo_path)
return logo_filename
# Generate a thumbnail for consistent navbar sizing
try:
thumb_filename = f'school-logo-{safe_tenant}-thumb.png'
thumb_path = os.path.join(app.config['UPLOAD_FOLDER'], thumb_filename)
with Image.open(logo_path) as img:
# Ensure RGBA for transparency and convert if needed
if img.mode not in ('RGBA', 'RGB'):
img = img.convert('RGBA')
# Target max size: width up to 520px, height up to 114px (matches CSS constraints)
max_thumb_size = (520, 114)
img.thumbnail(max_thumb_size, Image.LANCZOS)
# Save as PNG for predictable rendering in web UI
img.save(thumb_path, format='PNG', optimize=True)
except Exception as e:
app.logger.warning(f"Thumbnail generation failed for {logo_path}: {e}")
thumb_filename = None
return (logo_filename, thumb_filename)
def _parse_money_value(value):
@@ -1231,6 +1252,7 @@ def inject_version():
'current_permissions': current_permissions,
'current_tenant_db': current_tenant_db,
'current_tenant_id': current_tenant_id,
'school_info': _get_school_info_for_export(),
'permission_action_options': PERMISSION_ACTION_OPTIONS,
'permission_page_options': PERMISSION_PAGE_OPTIONS,
'permission_presets': us.get_permission_preset_definitions(),
@@ -9913,15 +9935,25 @@ def admin_school_settings():
'school_number': sanitize_form_value(request.form.get('school_number')),
'it_admin': sanitize_form_value(request.form.get('it_admin')),
'logo_path': sanitize_form_value(request.form.get('logo_path')),
'logo_thumb': sanitize_form_value(request.form.get('logo_thumb')),
}
uploaded_logo = request.files.get('logo_upload')
if uploaded_logo and getattr(uploaded_logo, 'filename', ''):
try:
previous_logo_path = current_school.get('logo_path') if isinstance(current_school, dict) else ''
saved_logo_filename = _save_school_logo_upload(uploaded_logo, tenant_id=tenant_id, tenant_db=tenant_db)
previous_thumb_path = current_school.get('logo_thumb') if isinstance(current_school, dict) else ''
saved = _save_school_logo_upload(uploaded_logo, tenant_id=tenant_id, tenant_db=tenant_db)
if isinstance(saved, (list, tuple)):
saved_logo_filename, saved_thumb_filename = saved
else:
saved_logo_filename, saved_thumb_filename = saved, None
if saved_logo_filename:
school_info['logo_path'] = saved_logo_filename
school_info['logo_thumb'] = saved_thumb_filename or ''
# remove previous files if different
if previous_logo_path and previous_logo_path != saved_logo_filename:
previous_logo_file = os.path.join(app.config['UPLOAD_FOLDER'], previous_logo_path)
if os.path.exists(previous_logo_file):
@@ -9929,12 +9961,21 @@ def admin_school_settings():
os.remove(previous_logo_file)
except Exception:
pass
if previous_thumb_path and previous_thumb_path != saved_thumb_filename:
previous_thumb_file = os.path.join(app.config['UPLOAD_FOLDER'], previous_thumb_path)
if os.path.exists(previous_thumb_file):
try:
os.remove(previous_thumb_file)
except Exception:
pass
except Exception as exc:
flash(f'Logo konnte nicht hochgeladen werden: {exc}', 'error')
return redirect(url_for('admin_school_settings'))
if not school_info.get('logo_path') and current_school.get('logo_path'):
school_info['logo_path'] = current_school.get('logo_path', '')
if not school_info.get('logo_thumb') and current_school.get('logo_thumb'):
school_info['logo_thumb'] = current_school.get('logo_thumb', '')
missing_fields = [
label for label, key in [
+2
View File
@@ -69,6 +69,8 @@ DEFAULTS = {
'school_number': '000000',
'it_admin': 'IT-Beauftragte oder IT-Beauftragter',
'logo_path': '',
'logo_thumb': '',
'logo_thumb': '',
},
'schoolPeriods': {
"1": {"start": "08:00", "end": "08:45", "label": "1. Stunde (08:00 - 08:45)"},
+17 -3
View File
@@ -1127,6 +1127,7 @@
{% if current_permissions.pages.get('manage_locations', True) %}
<li><a class="dropdown-item" href="{{ url_for('manage_locations') }}">Orte verwalten</a></li>
{% endif %}
<li><a class="dropdown-item" href="{{ url_for('admin_school_settings') }}">Schulstammdaten</a></li>
{% if current_permissions.pages.get('admin_borrowings', True) %}
<li><a class="dropdown-item" href="{{ url_for('admin_borrowings') }}">Ausleihen</a></li>
{% endif %}
@@ -1252,6 +1253,7 @@
{% if student_cards_module_enabled %}
<li><a class="dropdown-item" href="{{ url_for('student_cards_admin') }}">Bibliotheksausweis</a></li>
{% endif %}
<li><a class="dropdown-item" href="{{ url_for('admin_school_settings') }}">Schulstammdaten</a></li>
<li><hr class="dropdown-divider"></li>
{% if current_permissions.actions.get('can_manage_users', True) %}
<li><h6 class="dropdown-header">System</h6></li>
@@ -1311,9 +1313,19 @@
{% else %}
<nav class="navbar navbar-expand-lg navbar-dark" id="loginNavbar">
<div class="container-fluid">
<a class="navbar-brand py-0" href="{{ url_for('home') }}">
<img src="{{ url_for('static', filename='img/invario-logo.png') }}" alt="Invario" class="invario-logo">
</a>
<a class="navbar-brand py-0" href="{{ url_for('home') }}">
{% set school_logo_thumb = school_info.get('logo_thumb') if school_info else '' %}
{% set school_logo_path = school_info.get('logo_path') if school_info else '' %}
{% if school_logo_thumb or school_logo_path %}
{% if school_logo_thumb %}
<img src="{{ url_for('uploaded_file', filename=school_logo_thumb) }}" alt="{{ school_info.name or 'Schullogo' }}" class="invario-logo">
{% else %}
<img src="{{ url_for('uploaded_file', filename=school_logo_path) }}" alt="{{ school_info.name or 'Schullogo' }}" class="invario-logo">
{% endif %}
{% else %}
<img src="{{ url_for('static', filename='img/invario-logo.png') }}" alt="Invario" class="invario-logo">
{% endif %}
</a>
<ul class="navbar-nav ms-auto mb-2 mb-lg-0">
<li class="nav-item">
<a class="nav-link" href="{{ url_for('impressum') }}">Impressum</a>
@@ -1519,6 +1531,7 @@
<option value="Defekte Items"></option>
<option value="Filter verwalten"></option>
<option value="Orte verwalten"></option>
<option value="Schulstammdaten"></option>
<option value="Audit Dashboard"></option>
<option value="Logs"></option>
<option value="Benutzer verwalten"></option>
@@ -1588,6 +1601,7 @@
{ label: 'Defekte Items', keywords: ['defekte items', 'defekt', 'schaden'], url: {{ url_for('admin_damaged_items')|tojson }} },
{ label: 'Filter verwalten', keywords: ['filter verwalten', 'filter'], url: {{ url_for('manage_filters')|tojson }} },
{ label: 'Orte verwalten', keywords: ['orte verwalten', 'orte', 'location'], url: {{ url_for('manage_locations')|tojson }} },
{ label: 'Schulstammdaten', keywords: ['schule', 'settings', 'stammdaten', 'school settings'], url: {{ url_for('admin_school_settings')|tojson }} },
{ label: 'Audit Dashboard', keywords: ['audit', 'audit dashboard'], url: {{ url_for('admin_audit_dashboard')|tojson }} },
{ label: 'Logs', keywords: ['logs', 'protokoll'], url: {{ url_for('logs')|tojson }} },
{ label: 'Benutzer verwalten', keywords: ['benutzer verwalten', 'user'], url: {{ url_for('user_del')|tojson }} },
-4
View File
@@ -2353,10 +2353,6 @@ document.addEventListener('DOMContentLoaded', ()=>{
{% if school_info and school_info.school_number %} | Schulnummer: {{ school_info.school_number }}{% endif %}
</div>
</div>
<div style="display:flex; gap:10px; flex-wrap:wrap;">
<a href="{{ url_for('admin_school_settings') }}" class="btn btn-primary">Schulstammdaten bearbeiten</a>
<a href="{{ url_for('admin_audit') }}" class="btn btn-outline-secondary">Audit-Export öffnen</a>
</div>
</div>
<div id="items-indicator" class="items-indicator">Objekte im System: 0</div>
<div id="bulk-delete-drawer" class="bulk-delete-drawer" aria-hidden="true">