feat: Admin kann Email-Konten pro Benutzer verwalten + Benutzersuche

- Admin-Benutzer-Dialog hat jetzt zwei Tabs: Allgemein + E-Mail-Konten
- Im E-Mail-Konten-Tab: Konten fuer jeden Benutzer hinzufuegen,
  bearbeiten und loeschen (ohne sich als Benutzer einloggen zu muessen)
- Benutzersuche in der Benutzerverwaltung (filtert nach Name und Email)
- Backend: /admin/users/<id>/email-accounts GET/POST und
  /admin/email-accounts/<id> PUT/DELETE Endpunkte

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Stefan Hacker
2026-04-11 17:35:51 +02:00
parent 113fe7140f
commit 7220a2ef75
2 changed files with 305 additions and 30 deletions
+87 -1
View File
@@ -10,9 +10,10 @@ from datetime import datetime, timezone
from flask import request, jsonify, current_app
from app.api import api_bp
from app.api.auth import token_required
from app.api.auth import token_required, admin_required
from app.extensions import db
from app.models.email_account import EmailAccount
from app.models.user import User
from app.services.crypto_service import encrypt_field, decrypt_field
@@ -487,3 +488,88 @@ def delete_message(account_id, uid):
return jsonify({'message': 'Nachricht geloescht'}), 200
except Exception as e:
return jsonify({'error': str(e)}), 500
# --- Admin: manage email accounts for any user ---
@api_bp.route('/admin/users/<int:user_id>/email-accounts', methods=['GET'])
@admin_required
def admin_list_email_accounts(user_id):
user = db.session.get(User, user_id)
if not user:
return jsonify({'error': 'Benutzer nicht gefunden'}), 404
accounts = EmailAccount.query.filter_by(user_id=user_id)\
.order_by(EmailAccount.sort_order).all()
return jsonify([a.to_dict() for a in accounts]), 200
@api_bp.route('/admin/users/<int:user_id>/email-accounts', methods=['POST'])
@admin_required
def admin_create_email_account(user_id):
user = db.session.get(User, user_id)
if not user:
return jsonify({'error': 'Benutzer nicht gefunden'}), 404
data = request.get_json()
required = ['display_name', 'email_address', 'imap_host', 'smtp_host', 'username', 'password']
for field in required:
if not data.get(field):
return jsonify({'error': f'{field} erforderlich'}), 400
enc_key = request.headers.get('X-Encryption-Key', '')
if not enc_key:
return jsonify({'error': 'Verschluesselungs-Key erforderlich (X-Encryption-Key Header)'}), 400
account = EmailAccount(
user_id=user_id,
display_name=data['display_name'],
email_address=data['email_address'],
imap_host=data['imap_host'],
imap_port=data.get('imap_port', 993),
imap_ssl=data.get('imap_ssl', True),
smtp_host=data['smtp_host'],
smtp_port=data.get('smtp_port', 587),
smtp_ssl=data.get('smtp_ssl', True),
username=data['username'],
password_encrypted=encrypt_field(data['password'], enc_key),
is_default=data.get('is_default', False),
sort_order=data.get('sort_order', 0),
)
db.session.add(account)
db.session.commit()
return jsonify(account.to_dict()), 201
@api_bp.route('/admin/email-accounts/<int:account_id>', methods=['PUT'])
@admin_required
def admin_update_email_account(account_id):
account = db.session.get(EmailAccount, account_id)
if not account:
return jsonify({'error': 'Konto nicht gefunden'}), 404
data = request.get_json()
for field in ['display_name', 'email_address', 'imap_host', 'imap_port',
'imap_ssl', 'smtp_host', 'smtp_port', 'smtp_ssl',
'username', 'is_default', 'sort_order']:
if field in data:
setattr(account, field, data[field])
if 'password' in data and data['password']:
enc_key = request.headers.get('X-Encryption-Key', '')
if enc_key:
account.password_encrypted = encrypt_field(data['password'], enc_key)
db.session.commit()
return jsonify(account.to_dict()), 200
@api_bp.route('/admin/email-accounts/<int:account_id>', methods=['DELETE'])
@admin_required
def admin_delete_email_account(account_id):
account = db.session.get(EmailAccount, account_id)
if not account:
return jsonify({'error': 'Konto nicht gefunden'}), 404
db.session.delete(account)
db.session.commit()
return jsonify({'message': 'E-Mail-Konto geloescht'}), 200