'''
# === API ROUTES ===
@app.route('/api/login', methods=['POST'])
def login():
data = request.get_json() or {}
username = data.get('username', '').lower()
password = data.get('password', '')
password_hash = hash_password(password)
user = next((u for u in users if u['username'].lower() == username and
u['password_hash'] == password_hash and u.get('is_active', False)), None)
if user:
session['user_id'] = user['id']
user['last_login'] = datetime.now().isoformat()
return jsonify({
'status': 'ok',
'user': {'id': user['id'], 'name': user['name'], 'role': user['role']},
'force_password_change': user.get('force_password_change', False)
})
return jsonify({'error': 'Invalid username or password'}), 401
@app.route('/api/logout', methods=['POST'])
def logout():
session.pop('user_id', None)
return jsonify({'status': 'ok'})
# Passwort ändern
@app.route('/api/change-password', methods=['GET', 'POST'])
def change_password():
if 'user_id' not in session:
return jsonify({'error': 'Unauthorized'}), 401
user = next((u for u in users if u['id'] == session['user_id']), None)
if not user:
return jsonify({'error': 'User not found'}), 404
if request.method == 'GET':
return jsonify({
'force_change': user.get('force_password_change', False)
})
data = request.get_json() or {}
current_password = data.get('current_password', '')
new_password = data.get('new_password', '')
if hash_password(current_password) != user['password_hash']:
return jsonify({'error': 'Aktuelles Passwort ist falsch'}), 400
if len(new_password) < 8:
return jsonify({'error': 'Neues Passwort muss mindestens 8 Zeichen haben'}), 400
user['password_hash'] = hash_password(new_password)
user['force_password_change'] = False
try:
body = email_templates['password_changed'].format(name=user['name'])
send_email_smtp(user['email'], 'Ihr Passwort wurde geändert', body)
except Exception as e:
print(f"Password change email error: {e}")
return jsonify({'status': 'ok'})
@app.route('/api/me')
def get_current_user():
if 'user_id' not in session:
return jsonify({'error': 'Not logged in'}), 401
user = next((u for u in users if u['id'] == session['user_id']), None)
if not user:
return jsonify({'error': 'User not found'}), 404
return jsonify({
'user': {'id': user['id'], 'name': user['name'], 'role': user['role']},
'permissions': ROLE_PERMISSIONS.get(user['role'], [])
})
# Public API - Räume
@app.route('/api/public/rooms')
def public_get_rooms():
"""Öffentliche Raum-Liste (nicht blockierte Räume)"""
available = []
for room in rooms:
if not room.get('blocked', False):
available.append({
'id': room['id'],
'name': room['name'],
'description': room.get('description', ''),
'capacity': room.get('capacity', 0),
'tables': room['tables']
})
return jsonify({'rooms': available})
# Public API - Reservierung
@app.route('/api/public/reservations', methods=['POST'])
def public_create_reservation():
global reservations
data = request.get_json() or {}
# NEU: room_id statt table_ids
required = ['name', 'email', 'date', 'time', 'guests', 'room_id']
for field in required:
if not data.get(field):
return jsonify({'error': f'{field} is required'}), 400
if not re.match(r'^[^@]+@[^@]+\.[^@]+$', data['email']):
return jsonify({'error': 'Invalid email address'}), 400
room_id = int(data['room_id'])
guests = data['guests']
date_str = data['date']
time_str = data['time']
# Raum validieren
room = get_room(room_id)
if not room:
return jsonify({'error': 'Ungültiger Raum'}), 400
if room.get('blocked', False):
return jsonify({'error': 'Raum ist derzeit nicht verfügbar'}), 400
# Kapazität prüfen
if guests > room.get('capacity', 0):
return jsonify({'error': f'Zu viele Gäste für diesen Raum (max. {room["capacity"]})'}), 400
# Automatische Tisch-Zuweisung
table_ids, error = auto_assign_tables(room_id, guests, date_str, time_str)
if error:
return jsonify({'error': error}), 400
booking_id = generate_booking_id()
table_names = []
for table_id in table_ids:
table, _ = get_table(table_id)
if table:
table_names.append(table['name'])
reservation = {
'id': len(reservations) + 1,
'booking_id': booking_id,
'name': data['name'],
'email': data['email'],
'phone': data.get('phone', ''),
'date': date_str,
'time': time_str,
'guests': guests,
'room_id': room_id,
'room_name': room['name'],
'table_ids': table_ids,
'table_names': ', '.join(table_names),
'notes': data.get('notes', ''),
'created_at': datetime.now().isoformat()
}
reservations.append(reservation)
try:
email_body = email_templates['confirmation'].format(
name=data['name'],
booking_id=booking_id,
date=date_str,
time=time_str,
guests=guests,
room=room['name']
)
send_email_smtp(data['email'], f'Ihre Reservierung - {booking_id}', email_body)
except Exception as e:
print(f"Email error: {e}")
return jsonify({'status': 'ok', 'booking_id': booking_id})
# Admin API - Reservierungen
@app.route('/api/admin/reservations')
def admin_get_reservations():
if 'user_id' not in session:
return jsonify({'error': 'Unauthorized'}), 401
return jsonify({'reservations': reservations})
@app.route('/api/admin/reservations/search')
def admin_search_reservations():
if 'user_id' not in session:
return jsonify({'error': 'Unauthorized'}), 401
query = request.args.get('q', '').lower()
if not query:
return jsonify({'reservations': reservations})
results = [r for r in reservations if query in r.get('name', '').lower() or
query in r.get('email', '').lower() or query in r.get('booking_id', '').lower()]
return jsonify({'reservations': results})
# Admin API - Users
@app.route('/api/admin/users')
def admin_get_users():
if 'user_id' not in session:
return jsonify({'error': 'Unauthorized'}), 401
current = next((u for u in users if u['id'] == session['user_id']), None)
if not current or current['role'] != 'admin':
return jsonify({'error': 'Forbidden'}), 403
safe_users = [{'id': u['id'], 'username': u['username'], 'name': u['name'],
'email': u['email'], 'role': u['role'], 'is_active': u.get('is_active', True),
'last_login': u.get('last_login')} for u in users]
return jsonify({'users': safe_users})
@app.route('/api/admin/users', methods=['POST'])
def admin_create_user():
global users
if 'user_id' not in session:
return jsonify({'error': 'Unauthorized'}), 401
current = next((u for u in users if u['id'] == session['user_id']), None)
if not current or current['role'] != 'admin':
return jsonify({'error': 'Forbidden'}), 403
data = request.get_json() or {}
if not all(k in data for k in ['username', 'name', 'email', 'role']):
return jsonify({'error': 'Missing required fields'}), 400
if any(u['username'].lower() == data['username'].lower() for u in users):
return jsonify({'error': 'Username already exists'}), 400
temp_password = ''.join(random.choices(string.ascii_letters + string.digits, k=10))
new_user = {
'id': max([u['id'] for u in users], default=0) + 1,
'username': data['username'],
'password_hash': hash_password(temp_password),
'name': data['name'],
'email': data['email'],
'role': data['role'],
'is_active': True,
'force_password_change': True,
'created_at': datetime.now().isoformat(),
'last_login': None
}
users.append(new_user)
if data.get('send_email', True):
try:
body = email_templates['user_welcome'].format(
name=data['name'],
username=data['username'],
password=temp_password,
role=data['role']
)
send_email_smtp(data['email'], 'Ihr Reservierungssystem-Zugang', body)
except Exception as e:
print(f"Welcome email error: {e}")
return jsonify({'status': 'ok', 'temp_password': temp_password if not data.get('send_email') else None})
# Admin API - Räume (NEU)
@app.route('/api/admin/rooms')
def admin_get_rooms():
"""Liste aller Räume für Admins"""
if 'user_id' not in session:
return jsonify({'error': 'Unauthorized'}), 401
return jsonify({'rooms': rooms})
@app.route('/api/admin/rooms', methods=['POST'])
def admin_create_room():
global rooms
if 'user_id' not in session:
return jsonify({'error': 'Unauthorized'}), 401
data = request.get_json() or {}
if not data.get('name'):
return jsonify({'error': 'Name erforderlich'}), 400
capacity = data.get('capacity', 0)
if capacity < 1:
return jsonify({'error': 'Kapazität muss mindestens 1 sein'}), 400
new_room = {
'id': max([r['id'] for r in rooms], default=0) + 1,
'name': data['name'],
'description': data.get('description', ''),
'capacity': capacity,
'blocked': False,
'tables': []
}
rooms.append(new_room)
return jsonify({'status': 'ok', 'room': new_room})
@app.route('/api/admin/rooms/', methods=['PUT'])
def admin_update_room(room_id):
global rooms
if 'user_id' not in session:
return jsonify({'error': 'Unauthorized'}), 401
room = get_room(room_id)
if not room:
return jsonify({'error': 'Raum nicht gefunden'}), 404
data = request.get_json() or {}
if data.get('name'):
room['name'] = data['name']
if 'description' in data:
room['description'] = data['description']
if 'capacity' in data:
capacity = data['capacity']
if capacity < 1:
return jsonify({'error': 'Kapazität muss mindestens 1 sein'}), 400
room['capacity'] = capacity
return jsonify({'status': 'ok', 'room': room})
@app.route('/api/admin/rooms/', methods=['DELETE'])
def admin_delete_room(room_id):
global rooms, reservations
if 'user_id' not in session:
return jsonify({'error': 'Unauthorized'}), 401
room = get_room(room_id)
if not room:
return jsonify({'error': 'Raum nicht gefunden'}), 404
# Prüfe auf aktive Reservierungen für diesen Raum
active_reservations = [r for r in reservations if r.get('room_id') == room_id]
if active_reservations:
return jsonify({'error': f'Raum hat {len(active_reservations)} aktive Reservierungen'}), 400
rooms = [r for r in rooms if r['id'] != room_id]
return jsonify({'status': 'ok'})
@app.route('/api/admin/rooms//tables', methods=['POST'])
def admin_add_table(room_id):
global rooms
if 'user_id' not in session:
return jsonify({'error': 'Unauthorized'}), 401
room = get_room(room_id)
if not room:
return jsonify({'error': 'Raum nicht gefunden'}), 404
data = request.get_json() or {}
if not data.get('name'):
return jsonify({'error': 'Tischname erforderlich'}), 400
seats = data.get('seats', 0)
if seats < 1:
return jsonify({'error': 'Plätze müssen mindestens 1 sein'}), 400
# Generiere eindeutige Tisch-ID über alle Räume
max_table_id = 0
for r in rooms:
for t in r['tables']:
max_table_id = max(max_table_id, t['id'])
new_table = {
'id': max_table_id + 1,
'name': data['name'],
'seats': seats,
'shape': data.get('shape', 'rect')
}
room['tables'].append(new_table)
return jsonify({'status': 'ok', 'table': new_table})
@app.route('/api/admin/rooms//tables/', methods=['DELETE'])
def admin_delete_table(room_id, table_id):
global rooms
if 'user_id' not in session:
return jsonify({'error': 'Unauthorized'}), 401
room = get_room(room_id)
if not room:
return jsonify({'error': 'Raum nicht gefunden'}), 404
# Prüfe ob Tisch in Reservierungen verwendet wird
for res in reservations:
if table_id in res.get('table_ids', []):
return jsonify({'error': 'Tisch ist in einer Reservierung'}), 400
room['tables'] = [t for t in room['tables'] if t['id'] != table_id]
return jsonify({'status': 'ok'})
@app.route('/api/admin/rooms//block', methods=['POST'])
def admin_block_room(room_id):
global rooms
if 'user_id' not in session:
return jsonify({'error': 'Unauthorized'}), 401
room = get_room(room_id)
if not room:
return jsonify({'error': 'Raum nicht gefunden'}), 404
room['blocked'] = True
return jsonify({'status': 'ok'})
@app.route('/api/admin/rooms//unblock', methods=['POST'])
def admin_unblock_room(room_id):
global rooms
if 'user_id' not in session:
return jsonify({'error': 'Unauthorized'}), 401
room = get_room(room_id)
if not room:
return jsonify({'error': 'Raum nicht gefunden'}), 404
room['blocked'] = False
return jsonify({'status': 'ok'})
# Rooms API (für Admin-Dashboard)
@app.route('/api/rooms')
def get_rooms():
if 'user_id' not in session:
return jsonify({'error': 'Unauthorized'}), 401
return jsonify({'rooms': rooms})
# Templates & SMTP
@app.route('/api/admin/templates', methods=['GET', 'POST'])
def handle_templates():
global email_templates
if 'user_id' not in session:
return jsonify({'error': 'Unauthorized'}), 401
if request.method == 'POST':
data = request.get_json() or {}
if 'confirmation' in data:
email_templates['confirmation'] = data['confirmation']
if 'email_reply' in data:
email_templates['email_reply'] = data['email_reply']
return jsonify({'status': 'ok'})
return jsonify({'templates': email_templates})
@app.route('/api/admin/smtp', methods=['GET', 'POST'])
def handle_smtp():
global smtp_config
if 'user_id' not in session:
return jsonify({'error': 'Unauthorized'}), 401
if request.method == 'POST':
data = request.get_json() or {}
smtp_config.update(data)
return jsonify({'status': 'ok'})
return jsonify({
'host': smtp_config.get('host', ''),
'port': smtp_config.get('port', 587),
'user': smtp_config.get('user', ''),
'from': smtp_config.get('from', '')
})
@app.route('/api/admin/smtp/test', methods=['POST'])
def test_smtp():
if 'user_id' not in session:
return jsonify({'error': 'Unauthorized'}), 401
result = send_email_smtp(
smtp_config.get('user', 'test@example.com'),
'SMTP Test',
'Dies ist eine Testnachricht.'
)
if result:
return jsonify({'status': 'ok'})
return jsonify({'error': 'SMTP test failed'}), 500
# Main routes
@app.route('/')
def index():
if 'user_id' in session:
return redirect('/admin')
return render_template_string(PUBLIC_RESERVATION_HTML, min_date=str(date.today()))
@app.route('/admin')
def admin():
if 'user_id' not in session:
return render_template_string(ADMIN_LOGIN_HTML,
default_username='admin',
default_password='changeme',
force_password_change=False)
user = next((u for u in users if u['id'] == session['user_id']), None)
if not user:
session.pop('user_id', None)
return redirect('/admin')
return render_template_string(ADMIN_DASHBOARD_HTML,
template_confirmation=email_templates['confirmation'],
template_email_reply=email_templates['email_reply'],
smtp_host=smtp_config.get('host', ''),
smtp_port=smtp_config.get('port', 587),
smtp_user=smtp_config.get('user', ''),
smtp_password='***' if smtp_config.get('password') else '',
smtp_from=smtp_config.get('from', '')
)
@app.route('/change-password')
def change_password_page():
if 'user_id' not in session:
return redirect('/')
user = next((u for u in users if u['id'] == session['user_id']), None)
if not user:
session.pop('user_id', None)
return redirect('/')
return render_template_string(CHANGE_PASSWORD_HTML,
force_change=user.get('force_password_change', False))
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8080)