"feat: Integrate printer monitor for enhanced logging in backend"
This commit is contained in:
parent
81c2b2ab88
commit
482e04723d
@ -4344,4 +4344,536 @@ if __name__ == "__main__":
|
|||||||
stop_queue_manager()
|
stop_queue_manager()
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
# ===== FILE-UPLOAD-ROUTEN =====
|
||||||
|
|
||||||
|
@app.route('/api/upload/job', methods=['POST'])
|
||||||
|
@login_required
|
||||||
|
def upload_job_file():
|
||||||
|
"""
|
||||||
|
Lädt eine Datei für einen Druckjob hoch
|
||||||
|
|
||||||
|
Form Data:
|
||||||
|
file: Die hochzuladende Datei
|
||||||
|
job_name: Name des Jobs (optional)
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
if 'file' not in request.files:
|
||||||
|
return jsonify({'error': 'Keine Datei ausgewählt'}), 400
|
||||||
|
|
||||||
|
file = request.files['file']
|
||||||
|
job_name = request.form.get('job_name', '')
|
||||||
|
|
||||||
|
if file.filename == '':
|
||||||
|
return jsonify({'error': 'Keine Datei ausgewählt'}), 400
|
||||||
|
|
||||||
|
# Metadaten für die Datei
|
||||||
|
metadata = {
|
||||||
|
'uploader_id': current_user.id,
|
||||||
|
'uploader_name': current_user.username,
|
||||||
|
'job_name': job_name
|
||||||
|
}
|
||||||
|
|
||||||
|
# Datei speichern
|
||||||
|
result = save_job_file(file, current_user.id, metadata)
|
||||||
|
|
||||||
|
if result:
|
||||||
|
relative_path, absolute_path, file_metadata = result
|
||||||
|
|
||||||
|
app_logger.info(f"Job-Datei hochgeladen: {file_metadata['original_filename']} von User {current_user.id}")
|
||||||
|
|
||||||
|
return jsonify({
|
||||||
|
'success': True,
|
||||||
|
'message': 'Datei erfolgreich hochgeladen',
|
||||||
|
'file_path': relative_path,
|
||||||
|
'filename': file_metadata['original_filename'],
|
||||||
|
'unique_filename': file_metadata['unique_filename'],
|
||||||
|
'file_size': file_metadata['file_size'],
|
||||||
|
'metadata': file_metadata
|
||||||
|
})
|
||||||
|
else:
|
||||||
|
return jsonify({'error': 'Fehler beim Speichern der Datei'}), 500
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
app_logger.error(f"Fehler beim Hochladen der Job-Datei: {str(e)}")
|
||||||
|
return jsonify({'error': f'Fehler beim Hochladen: {str(e)}'}), 500
|
||||||
|
|
||||||
|
@app.route('/api/upload/guest', methods=['POST'])
|
||||||
|
def upload_guest_file():
|
||||||
|
"""
|
||||||
|
Lädt eine Datei für einen Gastauftrag hoch
|
||||||
|
|
||||||
|
Form Data:
|
||||||
|
file: Die hochzuladende Datei
|
||||||
|
guest_name: Name des Gasts (optional)
|
||||||
|
guest_email: E-Mail des Gasts (optional)
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
if 'file' not in request.files:
|
||||||
|
return jsonify({'error': 'Keine Datei ausgewählt'}), 400
|
||||||
|
|
||||||
|
file = request.files['file']
|
||||||
|
guest_name = request.form.get('guest_name', '')
|
||||||
|
guest_email = request.form.get('guest_email', '')
|
||||||
|
|
||||||
|
if file.filename == '':
|
||||||
|
return jsonify({'error': 'Keine Datei ausgewählt'}), 400
|
||||||
|
|
||||||
|
# Metadaten für die Datei
|
||||||
|
metadata = {
|
||||||
|
'guest_name': guest_name,
|
||||||
|
'guest_email': guest_email
|
||||||
|
}
|
||||||
|
|
||||||
|
# Datei speichern
|
||||||
|
result = save_guest_file(file, metadata)
|
||||||
|
|
||||||
|
if result:
|
||||||
|
relative_path, absolute_path, file_metadata = result
|
||||||
|
|
||||||
|
app_logger.info(f"Gast-Datei hochgeladen: {file_metadata['original_filename']} für {guest_name or 'Unbekannt'}")
|
||||||
|
|
||||||
|
return jsonify({
|
||||||
|
'success': True,
|
||||||
|
'message': 'Datei erfolgreich hochgeladen',
|
||||||
|
'file_path': relative_path,
|
||||||
|
'filename': file_metadata['original_filename'],
|
||||||
|
'unique_filename': file_metadata['unique_filename'],
|
||||||
|
'file_size': file_metadata['file_size'],
|
||||||
|
'metadata': file_metadata
|
||||||
|
})
|
||||||
|
else:
|
||||||
|
return jsonify({'error': 'Fehler beim Speichern der Datei'}), 500
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
app_logger.error(f"Fehler beim Hochladen der Gast-Datei: {str(e)}")
|
||||||
|
return jsonify({'error': f'Fehler beim Hochladen: {str(e)}'}), 500
|
||||||
|
|
||||||
|
@app.route('/api/upload/avatar', methods=['POST'])
|
||||||
|
@login_required
|
||||||
|
def upload_avatar():
|
||||||
|
"""
|
||||||
|
Lädt ein Avatar-Bild für den aktuellen Benutzer hoch
|
||||||
|
|
||||||
|
Form Data:
|
||||||
|
file: Das Avatar-Bild
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
if 'file' not in request.files:
|
||||||
|
return jsonify({'error': 'Keine Datei ausgewählt'}), 400
|
||||||
|
|
||||||
|
file = request.files['file']
|
||||||
|
|
||||||
|
if file.filename == '':
|
||||||
|
return jsonify({'error': 'Keine Datei ausgewählt'}), 400
|
||||||
|
|
||||||
|
# Nur Bilder erlauben
|
||||||
|
allowed_extensions = {'png', 'jpg', 'jpeg', 'gif', 'webp'}
|
||||||
|
if not file.filename or '.' not in file.filename:
|
||||||
|
return jsonify({'error': 'Ungültiger Dateityp'}), 400
|
||||||
|
|
||||||
|
file_ext = file.filename.rsplit('.', 1)[1].lower()
|
||||||
|
if file_ext not in allowed_extensions:
|
||||||
|
return jsonify({'error': 'Nur Bilddateien sind erlaubt (PNG, JPG, JPEG, GIF, WebP)'}), 400
|
||||||
|
|
||||||
|
# Alte Avatar-Datei löschen falls vorhanden
|
||||||
|
db_session = get_db_session()
|
||||||
|
user = db_session.query(User).get(current_user.id)
|
||||||
|
if user and user.avatar_path:
|
||||||
|
delete_file_safe(user.avatar_path)
|
||||||
|
|
||||||
|
# Neue Avatar-Datei speichern
|
||||||
|
result = save_avatar_file(file, current_user.id)
|
||||||
|
|
||||||
|
if result:
|
||||||
|
relative_path, absolute_path, file_metadata = result
|
||||||
|
|
||||||
|
# Avatar-Pfad in der Datenbank aktualisieren
|
||||||
|
user.avatar_path = relative_path
|
||||||
|
db_session.commit()
|
||||||
|
db_session.close()
|
||||||
|
|
||||||
|
app_logger.info(f"Avatar hochgeladen für User {current_user.id}")
|
||||||
|
|
||||||
|
return jsonify({
|
||||||
|
'success': True,
|
||||||
|
'message': 'Avatar erfolgreich hochgeladen',
|
||||||
|
'file_path': relative_path,
|
||||||
|
'filename': file_metadata['original_filename'],
|
||||||
|
'unique_filename': file_metadata['unique_filename'],
|
||||||
|
'file_size': file_metadata['file_size']
|
||||||
|
})
|
||||||
|
else:
|
||||||
|
db_session.close()
|
||||||
|
return jsonify({'error': 'Fehler beim Speichern des Avatars'}), 500
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
app_logger.error(f"Fehler beim Hochladen des Avatars: {str(e)}")
|
||||||
|
return jsonify({'error': f'Fehler beim Hochladen: {str(e)}'}), 500
|
||||||
|
|
||||||
|
@app.route('/api/upload/asset', methods=['POST'])
|
||||||
|
@login_required
|
||||||
|
@admin_required
|
||||||
|
def upload_asset():
|
||||||
|
"""
|
||||||
|
Lädt ein statisches Asset hoch (nur für Administratoren)
|
||||||
|
|
||||||
|
Form Data:
|
||||||
|
file: Die Asset-Datei
|
||||||
|
asset_name: Name des Assets (optional)
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
if 'file' not in request.files:
|
||||||
|
return jsonify({'error': 'Keine Datei ausgewählt'}), 400
|
||||||
|
|
||||||
|
file = request.files['file']
|
||||||
|
asset_name = request.form.get('asset_name', '')
|
||||||
|
|
||||||
|
if file.filename == '':
|
||||||
|
return jsonify({'error': 'Keine Datei ausgewählt'}), 400
|
||||||
|
|
||||||
|
# Metadaten für die Datei
|
||||||
|
metadata = {
|
||||||
|
'uploader_id': current_user.id,
|
||||||
|
'uploader_name': current_user.username,
|
||||||
|
'asset_name': asset_name
|
||||||
|
}
|
||||||
|
|
||||||
|
# Datei speichern
|
||||||
|
result = file_manager.save_file(file, 'assets', current_user.id, 'asset', metadata)
|
||||||
|
|
||||||
|
if result:
|
||||||
|
relative_path, absolute_path, file_metadata = result
|
||||||
|
|
||||||
|
app_logger.info(f"Asset hochgeladen: {file_metadata['original_filename']} von Admin {current_user.id}")
|
||||||
|
|
||||||
|
return jsonify({
|
||||||
|
'success': True,
|
||||||
|
'message': 'Asset erfolgreich hochgeladen',
|
||||||
|
'file_path': relative_path,
|
||||||
|
'filename': file_metadata['original_filename'],
|
||||||
|
'unique_filename': file_metadata['unique_filename'],
|
||||||
|
'file_size': file_metadata['file_size'],
|
||||||
|
'metadata': file_metadata
|
||||||
|
})
|
||||||
|
else:
|
||||||
|
return jsonify({'error': 'Fehler beim Speichern des Assets'}), 500
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
app_logger.error(f"Fehler beim Hochladen des Assets: {str(e)}")
|
||||||
|
return jsonify({'error': f'Fehler beim Hochladen: {str(e)}'}), 500
|
||||||
|
|
||||||
|
@app.route('/api/upload/log', methods=['POST'])
|
||||||
|
@login_required
|
||||||
|
@admin_required
|
||||||
|
def upload_log():
|
||||||
|
"""
|
||||||
|
Lädt eine Log-Datei hoch (nur für Administratoren)
|
||||||
|
|
||||||
|
Form Data:
|
||||||
|
file: Die Log-Datei
|
||||||
|
log_type: Typ des Logs (optional)
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
if 'file' not in request.files:
|
||||||
|
return jsonify({'error': 'Keine Datei ausgewählt'}), 400
|
||||||
|
|
||||||
|
file = request.files['file']
|
||||||
|
log_type = request.form.get('log_type', 'allgemein')
|
||||||
|
|
||||||
|
if file.filename == '':
|
||||||
|
return jsonify({'error': 'Keine Datei ausgewählt'}), 400
|
||||||
|
|
||||||
|
# Metadaten für die Datei
|
||||||
|
metadata = {
|
||||||
|
'uploader_id': current_user.id,
|
||||||
|
'uploader_name': current_user.username,
|
||||||
|
'log_type': log_type
|
||||||
|
}
|
||||||
|
|
||||||
|
# Datei speichern
|
||||||
|
result = file_manager.save_file(file, 'logs', current_user.id, 'log', metadata)
|
||||||
|
|
||||||
|
if result:
|
||||||
|
relative_path, absolute_path, file_metadata = result
|
||||||
|
|
||||||
|
app_logger.info(f"Log-Datei hochgeladen: {file_metadata['original_filename']} von Admin {current_user.id}")
|
||||||
|
|
||||||
|
return jsonify({
|
||||||
|
'success': True,
|
||||||
|
'message': 'Log-Datei erfolgreich hochgeladen',
|
||||||
|
'file_path': relative_path,
|
||||||
|
'filename': file_metadata['original_filename'],
|
||||||
|
'unique_filename': file_metadata['unique_filename'],
|
||||||
|
'file_size': file_metadata['file_size'],
|
||||||
|
'metadata': file_metadata
|
||||||
|
})
|
||||||
|
else:
|
||||||
|
return jsonify({'error': 'Fehler beim Speichern der Log-Datei'}), 500
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
app_logger.error(f"Fehler beim Hochladen der Log-Datei: {str(e)}")
|
||||||
|
return jsonify({'error': f'Fehler beim Hochladen: {str(e)}'}), 500
|
||||||
|
|
||||||
|
@app.route('/api/upload/backup', methods=['POST'])
|
||||||
|
@login_required
|
||||||
|
@admin_required
|
||||||
|
def upload_backup():
|
||||||
|
"""
|
||||||
|
Lädt eine Backup-Datei hoch (nur für Administratoren)
|
||||||
|
|
||||||
|
Form Data:
|
||||||
|
file: Die Backup-Datei
|
||||||
|
backup_type: Typ des Backups (optional)
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
if 'file' not in request.files:
|
||||||
|
return jsonify({'error': 'Keine Datei ausgewählt'}), 400
|
||||||
|
|
||||||
|
file = request.files['file']
|
||||||
|
backup_type = request.form.get('backup_type', 'allgemein')
|
||||||
|
|
||||||
|
if file.filename == '':
|
||||||
|
return jsonify({'error': 'Keine Datei ausgewählt'}), 400
|
||||||
|
|
||||||
|
# Metadaten für die Datei
|
||||||
|
metadata = {
|
||||||
|
'uploader_id': current_user.id,
|
||||||
|
'uploader_name': current_user.username,
|
||||||
|
'backup_type': backup_type
|
||||||
|
}
|
||||||
|
|
||||||
|
# Datei speichern
|
||||||
|
result = file_manager.save_file(file, 'backups', current_user.id, 'backup', metadata)
|
||||||
|
|
||||||
|
if result:
|
||||||
|
relative_path, absolute_path, file_metadata = result
|
||||||
|
|
||||||
|
app_logger.info(f"Backup-Datei hochgeladen: {file_metadata['original_filename']} von Admin {current_user.id}")
|
||||||
|
|
||||||
|
return jsonify({
|
||||||
|
'success': True,
|
||||||
|
'message': 'Backup-Datei erfolgreich hochgeladen',
|
||||||
|
'file_path': relative_path,
|
||||||
|
'filename': file_metadata['original_filename'],
|
||||||
|
'unique_filename': file_metadata['unique_filename'],
|
||||||
|
'file_size': file_metadata['file_size'],
|
||||||
|
'metadata': file_metadata
|
||||||
|
})
|
||||||
|
else:
|
||||||
|
return jsonify({'error': 'Fehler beim Speichern der Backup-Datei'}), 500
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
app_logger.error(f"Fehler beim Hochladen der Backup-Datei: {str(e)}")
|
||||||
|
return jsonify({'error': f'Fehler beim Hochladen: {str(e)}'}), 500
|
||||||
|
|
||||||
|
@app.route('/api/upload/temp', methods=['POST'])
|
||||||
|
@login_required
|
||||||
|
def upload_temp_file():
|
||||||
|
"""
|
||||||
|
Lädt eine temporäre Datei hoch
|
||||||
|
|
||||||
|
Form Data:
|
||||||
|
file: Die temporäre Datei
|
||||||
|
purpose: Verwendungszweck (optional)
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
if 'file' not in request.files:
|
||||||
|
return jsonify({'error': 'Keine Datei ausgewählt'}), 400
|
||||||
|
|
||||||
|
file = request.files['file']
|
||||||
|
purpose = request.form.get('purpose', '')
|
||||||
|
|
||||||
|
if file.filename == '':
|
||||||
|
return jsonify({'error': 'Keine Datei ausgewählt'}), 400
|
||||||
|
|
||||||
|
# Metadaten für die Datei
|
||||||
|
metadata = {
|
||||||
|
'uploader_id': current_user.id,
|
||||||
|
'uploader_name': current_user.username,
|
||||||
|
'purpose': purpose
|
||||||
|
}
|
||||||
|
|
||||||
|
# Datei speichern
|
||||||
|
result = file_manager.save_file(file, 'temp', current_user.id, 'temp', metadata)
|
||||||
|
|
||||||
|
if result:
|
||||||
|
relative_path, absolute_path, file_metadata = result
|
||||||
|
|
||||||
|
app_logger.info(f"Temporäre Datei hochgeladen: {file_metadata['original_filename']} von User {current_user.id}")
|
||||||
|
|
||||||
|
return jsonify({
|
||||||
|
'success': True,
|
||||||
|
'message': 'Temporäre Datei erfolgreich hochgeladen',
|
||||||
|
'file_path': relative_path,
|
||||||
|
'filename': file_metadata['original_filename'],
|
||||||
|
'unique_filename': file_metadata['unique_filename'],
|
||||||
|
'file_size': file_metadata['file_size'],
|
||||||
|
'metadata': file_metadata
|
||||||
|
})
|
||||||
|
else:
|
||||||
|
return jsonify({'error': 'Fehler beim Speichern der temporären Datei'}), 500
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
app_logger.error(f"Fehler beim Hochladen der temporären Datei: {str(e)}")
|
||||||
|
return jsonify({'error': f'Fehler beim Hochladen: {str(e)}'}), 500
|
||||||
|
|
||||||
|
@app.route('/api/files/<path:file_path>', methods=['GET'])
|
||||||
|
@login_required
|
||||||
|
def serve_uploaded_file(file_path):
|
||||||
|
"""
|
||||||
|
Stellt hochgeladene Dateien bereit (mit Zugriffskontrolle)
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
# Datei-Info abrufen
|
||||||
|
file_info = file_manager.get_file_info(file_path)
|
||||||
|
|
||||||
|
if not file_info:
|
||||||
|
return jsonify({'error': 'Datei nicht gefunden'}), 404
|
||||||
|
|
||||||
|
# Zugriffskontrolle basierend auf Dateikategorie
|
||||||
|
if file_path.startswith('jobs/'):
|
||||||
|
# Job-Dateien: Nur Besitzer und Admins
|
||||||
|
if not current_user.is_admin:
|
||||||
|
# Prüfen ob Benutzer der Besitzer ist
|
||||||
|
if f"user_{current_user.id}" not in file_path:
|
||||||
|
return jsonify({'error': 'Zugriff verweigert'}), 403
|
||||||
|
|
||||||
|
elif file_path.startswith('guests/'):
|
||||||
|
# Gast-Dateien: Nur Admins
|
||||||
|
if not current_user.is_admin:
|
||||||
|
return jsonify({'error': 'Zugriff verweigert'}), 403
|
||||||
|
|
||||||
|
elif file_path.startswith('avatars/'):
|
||||||
|
# Avatar-Dateien: Öffentlich zugänglich für angemeldete Benutzer
|
||||||
|
pass
|
||||||
|
|
||||||
|
elif file_path.startswith('temp/'):
|
||||||
|
# Temporäre Dateien: Nur Besitzer und Admins
|
||||||
|
if not current_user.is_admin:
|
||||||
|
# Prüfen ob Benutzer der Besitzer ist
|
||||||
|
if f"user_{current_user.id}" not in file_path:
|
||||||
|
return jsonify({'error': 'Zugriff verweigert'}), 403
|
||||||
|
|
||||||
|
else:
|
||||||
|
# Andere Dateien (assets, logs, backups): Nur Admins
|
||||||
|
if not current_user.is_admin:
|
||||||
|
return jsonify({'error': 'Zugriff verweigert'}), 403
|
||||||
|
|
||||||
|
# Datei bereitstellen
|
||||||
|
return send_file(file_info['absolute_path'], as_attachment=False)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
app_logger.error(f"Fehler beim Bereitstellen der Datei {file_path}: {str(e)}")
|
||||||
|
return jsonify({'error': 'Fehler beim Laden der Datei'}), 500
|
||||||
|
|
||||||
|
@app.route('/api/files/<path:file_path>', methods=['DELETE'])
|
||||||
|
@login_required
|
||||||
|
def delete_uploaded_file(file_path):
|
||||||
|
"""
|
||||||
|
Löscht eine hochgeladene Datei (mit Zugriffskontrolle)
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
# Datei-Info abrufen
|
||||||
|
file_info = file_manager.get_file_info(file_path)
|
||||||
|
|
||||||
|
if not file_info:
|
||||||
|
return jsonify({'error': 'Datei nicht gefunden'}), 404
|
||||||
|
|
||||||
|
# Zugriffskontrolle basierend auf Dateikategorie
|
||||||
|
if file_path.startswith('jobs/'):
|
||||||
|
# Job-Dateien: Nur Besitzer und Admins
|
||||||
|
if not current_user.is_admin:
|
||||||
|
# Prüfen ob Benutzer der Besitzer ist
|
||||||
|
if f"user_{current_user.id}" not in file_path:
|
||||||
|
return jsonify({'error': 'Zugriff verweigert'}), 403
|
||||||
|
|
||||||
|
elif file_path.startswith('guests/'):
|
||||||
|
# Gast-Dateien: Nur Admins
|
||||||
|
if not current_user.is_admin:
|
||||||
|
return jsonify({'error': 'Zugriff verweigert'}), 403
|
||||||
|
|
||||||
|
elif file_path.startswith('avatars/'):
|
||||||
|
# Avatar-Dateien: Nur Besitzer und Admins
|
||||||
|
if not current_user.is_admin:
|
||||||
|
# Prüfen ob Benutzer der Besitzer ist
|
||||||
|
if f"user_{current_user.id}" not in file_path:
|
||||||
|
return jsonify({'error': 'Zugriff verweigert'}), 403
|
||||||
|
|
||||||
|
elif file_path.startswith('temp/'):
|
||||||
|
# Temporäre Dateien: Nur Besitzer und Admins
|
||||||
|
if not current_user.is_admin:
|
||||||
|
# Prüfen ob Benutzer der Besitzer ist
|
||||||
|
if f"user_{current_user.id}" not in file_path:
|
||||||
|
return jsonify({'error': 'Zugriff verweigert'}), 403
|
||||||
|
|
||||||
|
else:
|
||||||
|
# Andere Dateien (assets, logs, backups): Nur Admins
|
||||||
|
if not current_user.is_admin:
|
||||||
|
return jsonify({'error': 'Zugriff verweigert'}), 403
|
||||||
|
|
||||||
|
# Datei löschen
|
||||||
|
if delete_file_safe(file_path):
|
||||||
|
app_logger.info(f"Datei gelöscht: {file_path} von User {current_user.id}")
|
||||||
|
return jsonify({'success': True, 'message': 'Datei erfolgreich gelöscht'})
|
||||||
|
else:
|
||||||
|
return jsonify({'error': 'Fehler beim Löschen der Datei'}), 500
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
app_logger.error(f"Fehler beim Löschen der Datei {file_path}: {str(e)}")
|
||||||
|
return jsonify({'error': f'Fehler beim Löschen der Datei: {str(e)}'}), 500
|
||||||
|
|
||||||
|
@app.route('/api/admin/files/stats', methods=['GET'])
|
||||||
|
@login_required
|
||||||
|
@admin_required
|
||||||
|
def get_file_stats():
|
||||||
|
"""
|
||||||
|
Gibt Statistiken zu allen Dateien zurück (nur für Administratoren)
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
stats = file_manager.get_category_stats()
|
||||||
|
|
||||||
|
# Gesamtstatistiken berechnen
|
||||||
|
total_files = sum(category.get('file_count', 0) for category in stats.values())
|
||||||
|
total_size = sum(category.get('total_size', 0) for category in stats.values())
|
||||||
|
|
||||||
|
return jsonify({
|
||||||
|
'success': True,
|
||||||
|
'categories': stats,
|
||||||
|
'totals': {
|
||||||
|
'file_count': total_files,
|
||||||
|
'total_size': total_size,
|
||||||
|
'total_size_mb': round(total_size / (1024 * 1024), 2)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
app_logger.error(f"Fehler beim Abrufen der Datei-Statistiken: {str(e)}")
|
||||||
|
return jsonify({'error': f'Fehler beim Abrufen der Statistiken: {str(e)}'}), 500
|
||||||
|
|
||||||
|
@app.route('/api/admin/files/cleanup', methods=['POST'])
|
||||||
|
@login_required
|
||||||
|
@admin_required
|
||||||
|
def cleanup_temp_files():
|
||||||
|
"""
|
||||||
|
Räumt temporäre Dateien auf (nur für Administratoren)
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
data = request.get_json() or {}
|
||||||
|
max_age_hours = data.get('max_age_hours', 24)
|
||||||
|
|
||||||
|
# Temporäre Dateien aufräumen
|
||||||
|
deleted_count = file_manager.cleanup_temp_files(max_age_hours)
|
||||||
|
|
||||||
|
app_logger.info(f"Temporäre Dateien aufgeräumt: {deleted_count} Dateien gelöscht")
|
||||||
|
|
||||||
|
return jsonify({
|
||||||
|
'success': True,
|
||||||
|
'message': f'{deleted_count} temporäre Dateien erfolgreich gelöscht',
|
||||||
|
'deleted_count': deleted_count
|
||||||
|
})
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
app_logger.error(f"Fehler beim Aufräumen temporärer Dateien: {str(e)}")
|
||||||
|
return jsonify({'error': f'Fehler beim Aufräumen: {str(e)}'}), 500
|
@ -138,8 +138,15 @@ class PrinterMonitor:
|
|||||||
monitor_logger.error("⚠️ PyP100-Modul nicht verfügbar - kann Tapo-Steckdose nicht schalten")
|
monitor_logger.error("⚠️ PyP100-Modul nicht verfügbar - kann Tapo-Steckdose nicht schalten")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
# Fallback zu globalen Anmeldedaten wenn keine lokalen vorhanden
|
||||||
|
if not username or not password:
|
||||||
|
username = TAPO_USERNAME
|
||||||
|
password = TAPO_PASSWORD
|
||||||
|
monitor_logger.debug(f"🔧 Verwende globale Tapo-Anmeldedaten für {ip_address}")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# TP-Link Tapo P100 Verbindung herstellen (P100 statt P110 verwenden)
|
# TP-Link Tapo P100 Verbindung herstellen (P100 statt P110 verwenden)
|
||||||
|
from PyP100 import PyP100
|
||||||
p100 = PyP100.P100(ip_address, username, password)
|
p100 = PyP100.P100(ip_address, username, password)
|
||||||
p100.handshake() # Authentifizierung
|
p100.handshake() # Authentifizierung
|
||||||
p100.login() # Login
|
p100.login() # Login
|
||||||
@ -342,7 +349,7 @@ class PrinterMonitor:
|
|||||||
def _ping_address(self, ip_address: str, timeout: int = 3) -> bool:
|
def _ping_address(self, ip_address: str, timeout: int = 3) -> bool:
|
||||||
"""
|
"""
|
||||||
Führt einen Konnektivitätstest zu einer IP-Adresse durch.
|
Führt einen Konnektivitätstest zu einer IP-Adresse durch.
|
||||||
Verwendet TCP-Verbindung statt Ping, um Encoding-Probleme zu vermeiden.
|
Verwendet ausschließlich TCP-Verbindung statt Ping, um Encoding-Probleme zu vermeiden.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
ip_address: Zu testende IP-Adresse
|
ip_address: Zu testende IP-Adresse
|
||||||
@ -355,10 +362,18 @@ class PrinterMonitor:
|
|||||||
# IP-Adresse validieren
|
# IP-Adresse validieren
|
||||||
ipaddress.ip_address(ip_address.strip())
|
ipaddress.ip_address(ip_address.strip())
|
||||||
|
|
||||||
# TCP-Verbindung zu Port 80 (HTTP) oder 443 (HTTPS) versuchen
|
|
||||||
import socket
|
import socket
|
||||||
|
|
||||||
# Erst Port 80 versuchen (HTTP)
|
# Erst Port 9999 versuchen (Tapo-Standard)
|
||||||
|
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
sock.settimeout(timeout)
|
||||||
|
result = sock.connect_ex((ip_address.strip(), 9999))
|
||||||
|
sock.close()
|
||||||
|
|
||||||
|
if result == 0:
|
||||||
|
return True
|
||||||
|
|
||||||
|
# Falls Port 9999 nicht erfolgreich, Port 80 versuchen (HTTP)
|
||||||
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
sock.settimeout(timeout)
|
sock.settimeout(timeout)
|
||||||
result = sock.connect_ex((ip_address.strip(), 80))
|
result = sock.connect_ex((ip_address.strip(), 80))
|
||||||
@ -481,15 +496,16 @@ class PrinterMonitor:
|
|||||||
|
|
||||||
for ip in DEFAULT_TAPO_IPS:
|
for ip in DEFAULT_TAPO_IPS:
|
||||||
try:
|
try:
|
||||||
# Ping-Test für Grundkonnektivität
|
# TCP-Verbindungstest für Grundkonnektivität
|
||||||
ping_success = self._ping_address(ip, timeout=2)
|
ping_success = self._ping_address(ip, timeout=3)
|
||||||
|
|
||||||
if ping_success:
|
if ping_success:
|
||||||
monitor_logger.info(f"✅ Steckdose mit IP {ip} ist pingbar")
|
monitor_logger.info(f"✅ Steckdose mit IP {ip} ist erreichbar")
|
||||||
|
|
||||||
# Tapo-Verbindung testen
|
# Tapo-Verbindung testen
|
||||||
if TAPO_AVAILABLE:
|
if TAPO_AVAILABLE:
|
||||||
try:
|
try:
|
||||||
|
from PyP100 import PyP100
|
||||||
p100 = PyP100.P100(ip, TAPO_USERNAME, TAPO_PASSWORD)
|
p100 = PyP100.P100(ip, TAPO_USERNAME, TAPO_PASSWORD)
|
||||||
p100.handshake()
|
p100.handshake()
|
||||||
p100.login()
|
p100.login()
|
||||||
@ -506,7 +522,7 @@ class PrinterMonitor:
|
|||||||
self._ensure_tapo_in_database(ip, nickname)
|
self._ensure_tapo_in_database(ip, nickname)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
monitor_logger.debug(f"❌ IP {ip} ist pingbar, aber keine Tapo-Steckdose: {str(e)}")
|
monitor_logger.debug(f"❌ IP {ip} ist erreichbar, aber keine Tapo-Steckdose: {str(e)}")
|
||||||
results[ip] = False
|
results[ip] = False
|
||||||
else:
|
else:
|
||||||
monitor_logger.warning("⚠️ PyP100-Modul nicht verfügbar - kann Tapo-Verbindung nicht testen")
|
monitor_logger.warning("⚠️ PyP100-Modul nicht verfügbar - kann Tapo-Verbindung nicht testen")
|
||||||
|
Loading…
x
Reference in New Issue
Block a user