'''
# === 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)
})
# POST: Passwort ändern
data = request.get_json() or {}
current_password = data.get('current_password', '')
new_password = data.get('new_password', '')
# Validate current password
if hash_password(current_password) != user['password_hash']:
return jsonify({'error': 'Aktuelles Passwort ist falsch'}), 400
# Validate new password
if len(new_password) < 8:
return jsonify({'error': 'Neues Passwort muss mindestens 8 Zeichen haben'}), 400
# Update password
user['password_hash'] = hash_password(new_password)
user['force_password_change'] = False
# Send confirmation email
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
@app.route('/api/public/tables')
def public_get_tables():
date_str = request.args.get('date', str(date.today()))
time_str = request.args.get('time', '19:00')
available = get_available_tables(date_str, time_str)
return jsonify({'tables': available})
@app.route('/api/public/reservations', methods=['POST'])
def public_create_reservation():
global reservations
data = request.get_json() or {}
required = ['name', 'email', 'date', 'time', 'guests', 'table_ids']
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
booking_id = generate_booking_id()
table_names = []
for table_id in data['table_ids']:
table, room = get_table(table_id)
if table:
table_names.append(f"{room['name']}/{table['name']}" if room else table['name'])
reservation = {
'id': len(reservations) + 1,
'booking_id': booking_id,
'name': data['name'],
'email': data['email'],
'phone': data.get('phone', ''),
'date': data['date'],
'time': data['time'],
'guests': data['guests'],
'table_ids': data['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=data['date'],
time=data['time'],
guests=data['guests'],
tables=', '.join(table_names)
)
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
@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})
# Users API
@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, # Muss Passwort bei erstem Login ändern
'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})
# Rooms, Templates, SMTP API
@app.route('/api/rooms')
def get_rooms():
if 'user_id' not in session:
return jsonify({'error': 'Unauthorized'}), 401
return jsonify({'rooms': rooms})
@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)