Merge branch 'main' of https://git.clickcandit.com/marwinm/website
This commit is contained in:
27
Dockerfile
27
Dockerfile
@@ -1,10 +1,27 @@
|
|||||||
FROM python:3.9-slim-buster
|
FROM python:3.11-slim
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
COPY requirements.txt requirements.txt
|
# System dependencies
|
||||||
RUN pip install -r requirements.txt
|
RUN apt-get update && apt-get install -y \
|
||||||
|
gcc \
|
||||||
|
python3-dev \
|
||||||
|
libffi-dev \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
COPY website .
|
# Clean up and install requirements
|
||||||
|
RUN rm -rf /app/*
|
||||||
|
COPY requirements.txt .
|
||||||
|
RUN pip install --no-cache-dir -r requirements.txt \
|
||||||
|
&& pip install --no-cache-dir wheel setuptools
|
||||||
|
|
||||||
CMD ["python", "app.py"]
|
# Copy application files
|
||||||
|
COPY website/ ./website/
|
||||||
|
COPY requirements.txt .
|
||||||
|
|
||||||
|
EXPOSE 6000
|
||||||
|
|
||||||
|
# Verify installations
|
||||||
|
RUN pip list
|
||||||
|
|
||||||
|
CMD ["python", "website/app.py"]
|
||||||
@@ -1,7 +1,16 @@
|
|||||||
version: "3.9"
|
version: '3.8'
|
||||||
|
|
||||||
services:
|
services:
|
||||||
web:
|
web:
|
||||||
build: .
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: Dockerfile
|
||||||
ports:
|
ports:
|
||||||
- "5000:5000"
|
- "6000:6000"
|
||||||
|
volumes:
|
||||||
|
- ./website:/app/website
|
||||||
|
environment:
|
||||||
|
- FLASK_ENV=development
|
||||||
|
- FLASK_DEBUG=1
|
||||||
|
command: python website/app.py
|
||||||
restart: always
|
restart: always
|
||||||
BIN
instance/mindmap.db
Normal file
BIN
instance/mindmap.db
Normal file
Binary file not shown.
@@ -1,6 +1,6 @@
|
|||||||
flask
|
Flask
|
||||||
flask-login
|
Flask-Login
|
||||||
flask-wtf
|
Flask-SQLAlchemy
|
||||||
email-validator
|
Werkzeug
|
||||||
python-dotenv
|
SQLAlchemy
|
||||||
flask-sqlalchemy
|
email_validator
|
||||||
119
start-flask-server.py
Normal file
119
start-flask-server.py
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
import subprocess
|
||||||
|
import webbrowser
|
||||||
|
import requests
|
||||||
|
import socket
|
||||||
|
import logging
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
# Configure logging
|
||||||
|
logging.basicConfig(
|
||||||
|
level=logging.INFO,
|
||||||
|
format='%(asctime)s - %(levelname)s - %(message)s',
|
||||||
|
datefmt='%Y-%m-%d %H:%M:%S'
|
||||||
|
)
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
def is_port_in_use(port):
|
||||||
|
"""Check if a port is already in use"""
|
||||||
|
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
|
||||||
|
return s.connect_ex(('127.0.0.1', port)) == 0
|
||||||
|
|
||||||
|
def wait_for_server(url, max_attempts=5, delay=1):
|
||||||
|
"""Wait for the server to start responding"""
|
||||||
|
for i in range(max_attempts):
|
||||||
|
try:
|
||||||
|
response = requests.get(url, timeout=2)
|
||||||
|
if response.status_code == 200:
|
||||||
|
logger.info(f"Server is up and running at {url}")
|
||||||
|
return True
|
||||||
|
except requests.exceptions.RequestException:
|
||||||
|
logger.info(f"Waiting for server to start (attempt {i+1}/{max_attempts})...")
|
||||||
|
time.sleep(delay)
|
||||||
|
return False
|
||||||
|
|
||||||
|
def main():
|
||||||
|
# Get the current directory
|
||||||
|
current_dir = Path(__file__).parent.absolute()
|
||||||
|
website_dir = current_dir / 'website'
|
||||||
|
|
||||||
|
# Check if website directory exists
|
||||||
|
if not website_dir.exists():
|
||||||
|
logger.error(f"Website directory not found: {website_dir}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Flask server details
|
||||||
|
host = "127.0.0.1"
|
||||||
|
port = 5000
|
||||||
|
url = f"http://{host}:{port}"
|
||||||
|
|
||||||
|
# Check if the port is already in use
|
||||||
|
if is_port_in_use(port):
|
||||||
|
logger.warning(f"Port {port} is already in use. There might be another server running.")
|
||||||
|
answer = input("Would you like to try to connect to the existing server? (y/n): ")
|
||||||
|
if answer.lower() == 'y':
|
||||||
|
webbrowser.open(url)
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
logger.info("Please stop the other server and try again.")
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Path to the run.py script
|
||||||
|
run_script = website_dir / 'run.py'
|
||||||
|
|
||||||
|
# Check if run.py exists
|
||||||
|
if not run_script.exists():
|
||||||
|
logger.error(f"Run script not found: {run_script}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Start the Flask server in a separate process
|
||||||
|
logger.info(f"Starting Flask server from {run_script}...")
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Use Python executable from the current environment
|
||||||
|
python_exe = sys.executable
|
||||||
|
|
||||||
|
# Start the server as a separate process
|
||||||
|
server_process = subprocess.Popen(
|
||||||
|
[python_exe, str(run_script)],
|
||||||
|
cwd=str(website_dir),
|
||||||
|
stdout=subprocess.PIPE,
|
||||||
|
stderr=subprocess.STDOUT,
|
||||||
|
text=True,
|
||||||
|
bufsize=1
|
||||||
|
)
|
||||||
|
|
||||||
|
# Wait for server to start
|
||||||
|
server_started = wait_for_server(url, max_attempts=10, delay=2)
|
||||||
|
|
||||||
|
if server_started:
|
||||||
|
logger.info("Opening web browser...")
|
||||||
|
webbrowser.open(url)
|
||||||
|
|
||||||
|
# Keep the server running and display its output
|
||||||
|
logger.info("Server is running. Press Ctrl+C to stop.")
|
||||||
|
try:
|
||||||
|
for line in server_process.stdout:
|
||||||
|
print(line.strip())
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
logger.info("Stopping server...")
|
||||||
|
server_process.terminate()
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
logger.error("Failed to start the server or server not responding")
|
||||||
|
server_process.terminate()
|
||||||
|
return False
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error starting Flask server: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
success = main()
|
||||||
|
if not success:
|
||||||
|
print("\nPress Enter to exit...")
|
||||||
|
input()
|
||||||
|
sys.exit(0 if success else 1)
|
||||||
72
start.sh
Normal file
72
start.sh
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Farben für die Ausgabe
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
RED='\033[0;31m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
NC='\033[0m' # No Color
|
||||||
|
|
||||||
|
# Funktion zum Anzeigen des Hilfetexts
|
||||||
|
show_help() {
|
||||||
|
echo -e "${YELLOW}Verwendung: ./start.sh [Option]${NC}"
|
||||||
|
echo "Optionen:"
|
||||||
|
echo " start - Startet die Container"
|
||||||
|
echo " stop - Stoppt die Container"
|
||||||
|
echo " restart - Neustart der Container"
|
||||||
|
echo " rebuild - Baut die Container neu"
|
||||||
|
echo " clean - Entfernt alle Container und Images"
|
||||||
|
echo " logs - Zeigt die Container-Logs"
|
||||||
|
echo " help - Zeigt diese Hilfe"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Prüfen ob Docker läuft
|
||||||
|
check_docker() {
|
||||||
|
if ! docker info > /dev/null 2>&1; then
|
||||||
|
echo -e "${RED}Error: Docker ist nicht gestartet${NC}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
case "$1" in
|
||||||
|
start)
|
||||||
|
check_docker
|
||||||
|
echo -e "${GREEN}Starte Container...${NC}"
|
||||||
|
docker-compose up -d
|
||||||
|
echo -e "${GREEN}Container erfolgreich gestartet!${NC}"
|
||||||
|
;;
|
||||||
|
stop)
|
||||||
|
check_docker
|
||||||
|
echo -e "${YELLOW}Stoppe Container...${NC}"
|
||||||
|
docker-compose down
|
||||||
|
echo -e "${GREEN}Container erfolgreich gestoppt!${NC}"
|
||||||
|
;;
|
||||||
|
restart)
|
||||||
|
check_docker
|
||||||
|
echo -e "${YELLOW}Neustart der Container...${NC}"
|
||||||
|
docker-compose down
|
||||||
|
docker-compose up -d
|
||||||
|
echo -e "${GREEN}Container erfolgreich neugestartet!${NC}"
|
||||||
|
;;
|
||||||
|
rebuild)
|
||||||
|
check_docker
|
||||||
|
echo -e "${YELLOW}Baue Container neu...${NC}"
|
||||||
|
docker-compose down --rmi all
|
||||||
|
docker-compose build --no-cache
|
||||||
|
docker-compose up -d
|
||||||
|
echo -e "${GREEN}Container erfolgreich neu gebaut!${NC}"
|
||||||
|
;;
|
||||||
|
clean)
|
||||||
|
check_docker
|
||||||
|
echo -e "${RED}Entferne alle Container und Images...${NC}"
|
||||||
|
docker-compose down --rmi all -v
|
||||||
|
echo -e "${GREEN}Aufräumen abgeschlossen!${NC}"
|
||||||
|
;;
|
||||||
|
logs)
|
||||||
|
check_docker
|
||||||
|
echo -e "${YELLOW}Container-Logs:${NC}"
|
||||||
|
docker-compose logs -f
|
||||||
|
;;
|
||||||
|
help|*)
|
||||||
|
show_help
|
||||||
|
;;
|
||||||
|
esac
|
||||||
5
start_server.bat
Normal file
5
start_server.bat
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
@echo off
|
||||||
|
cd website
|
||||||
|
echo Starting Flask server on http://127.0.0.1:5000
|
||||||
|
python run.py
|
||||||
|
pause
|
||||||
25
test_server.py
Normal file
25
test_server.py
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import requests
|
||||||
|
import time
|
||||||
|
|
||||||
|
def test_flask_server():
|
||||||
|
"""Test if the Flask server is accessible at http://127.0.0.1:5000"""
|
||||||
|
url = "http://127.0.0.1:5000"
|
||||||
|
|
||||||
|
print(f"Testing connection to Flask server at {url}")
|
||||||
|
|
||||||
|
for i in range(3):
|
||||||
|
try:
|
||||||
|
response = requests.get(url, timeout=5)
|
||||||
|
print(f"SUCCESS! Status code: {response.status_code}")
|
||||||
|
return True
|
||||||
|
except requests.exceptions.RequestException as e:
|
||||||
|
print(f"Attempt {i+1} failed: {e}")
|
||||||
|
if i < 2:
|
||||||
|
print("Waiting 2 seconds and trying again...")
|
||||||
|
time.sleep(2)
|
||||||
|
|
||||||
|
print("Failed to connect to the Flask server after 3 attempts")
|
||||||
|
return False
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
test_flask_server()
|
||||||
Binary file not shown.
BIN
website/__pycache__/app.cpython-313.pyc
Normal file
BIN
website/__pycache__/app.cpython-313.pyc
Normal file
Binary file not shown.
Binary file not shown.
BIN
website/__pycache__/init_db.cpython-313.pyc
Normal file
BIN
website/__pycache__/init_db.cpython-313.pyc
Normal file
Binary file not shown.
434
website/app.py
434
website/app.py
@@ -6,15 +6,231 @@ from flask_sqlalchemy import SQLAlchemy
|
|||||||
from werkzeug.security import generate_password_hash, check_password_hash
|
from werkzeug.security import generate_password_hash, check_password_hash
|
||||||
import json
|
import json
|
||||||
|
|
||||||
app = Flask(__name__)
|
db = SQLAlchemy()
|
||||||
app.config['SECRET_KEY'] = os.environ.get('SECRET_KEY', 'default-dev-key')
|
login_manager = LoginManager()
|
||||||
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///mindmap.db'
|
|
||||||
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
|
|
||||||
|
|
||||||
db = SQLAlchemy(app)
|
|
||||||
login_manager = LoginManager(app)
|
|
||||||
login_manager.login_view = 'login'
|
login_manager.login_view = 'login'
|
||||||
|
|
||||||
|
def create_app():
|
||||||
|
app = Flask(__name__)
|
||||||
|
app.config['SECRET_KEY'] = os.environ.get('SECRET_KEY', 'default-dev-key')
|
||||||
|
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///mindmap.db'
|
||||||
|
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
|
||||||
|
|
||||||
|
db.init_app(app)
|
||||||
|
login_manager.init_app(app)
|
||||||
|
|
||||||
|
with app.app_context():
|
||||||
|
# Initialize database and create root node
|
||||||
|
db.create_all()
|
||||||
|
try:
|
||||||
|
root = MindMapNode.query.filter_by(parent_id=None).first()
|
||||||
|
if not root:
|
||||||
|
root = MindMapNode(name="Wissenschaft")
|
||||||
|
db.session.add(root)
|
||||||
|
db.session.commit()
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error initializing database: {str(e)}")
|
||||||
|
|
||||||
|
# Register all routes with the app
|
||||||
|
@login_manager.user_loader
|
||||||
|
def load_user(id):
|
||||||
|
return User.query.get(int(id))
|
||||||
|
|
||||||
|
@app.route('/login', methods=['GET', 'POST'])
|
||||||
|
def login():
|
||||||
|
if request.method == 'POST':
|
||||||
|
username = request.form.get('username')
|
||||||
|
password = request.form.get('password')
|
||||||
|
|
||||||
|
user = User.query.filter_by(username=username).first()
|
||||||
|
if user and user.check_password(password):
|
||||||
|
login_user(user)
|
||||||
|
next_page = request.args.get('next')
|
||||||
|
return redirect(next_page or url_for('index'))
|
||||||
|
flash('Ungültiger Benutzername oder Passwort')
|
||||||
|
return render_template('login.html')
|
||||||
|
|
||||||
|
@app.route('/register', methods=['GET', 'POST'])
|
||||||
|
def register():
|
||||||
|
if request.method == 'POST':
|
||||||
|
username = request.form.get('username')
|
||||||
|
email = request.form.get('email')
|
||||||
|
password = request.form.get('password')
|
||||||
|
|
||||||
|
if User.query.filter_by(username=username).first():
|
||||||
|
flash('Benutzername existiert bereits')
|
||||||
|
return redirect(url_for('register'))
|
||||||
|
|
||||||
|
if User.query.filter_by(email=email).first():
|
||||||
|
flash('E-Mail ist bereits registriert')
|
||||||
|
return redirect(url_for('register'))
|
||||||
|
|
||||||
|
user = User(username=username, email=email)
|
||||||
|
user.set_password(password)
|
||||||
|
db.session.add(user)
|
||||||
|
db.session.commit()
|
||||||
|
|
||||||
|
login_user(user)
|
||||||
|
return redirect(url_for('index'))
|
||||||
|
return render_template('register.html')
|
||||||
|
|
||||||
|
@app.route('/logout')
|
||||||
|
@login_required
|
||||||
|
def logout():
|
||||||
|
logout_user()
|
||||||
|
return redirect(url_for('index'))
|
||||||
|
|
||||||
|
@app.route('/')
|
||||||
|
def index():
|
||||||
|
return render_template('index.html')
|
||||||
|
|
||||||
|
@app.route('/mindmap')
|
||||||
|
def mindmap():
|
||||||
|
try:
|
||||||
|
root_node = MindMapNode.query.filter_by(parent_id=None).first()
|
||||||
|
if not root_node:
|
||||||
|
root_node = MindMapNode(name="Wissenschaft")
|
||||||
|
db.session.add(root_node)
|
||||||
|
db.session.commit()
|
||||||
|
return render_template('mindmap.html')
|
||||||
|
except Exception as e:
|
||||||
|
app.logger.error(f"Error loading mindmap: {str(e)}")
|
||||||
|
return render_template('mindmap.html', error="Fehler beim Laden der Mindmap. Bitte versuchen Sie es erneut.")
|
||||||
|
|
||||||
|
@app.route('/profile')
|
||||||
|
@login_required
|
||||||
|
def profile():
|
||||||
|
thoughts = Thought.query.filter_by(user_id=current_user.id).order_by(Thought.timestamp.desc()).all()
|
||||||
|
return render_template('profile.html', thoughts=thoughts)
|
||||||
|
|
||||||
|
@app.route('/api/mindmap')
|
||||||
|
def get_mindmap():
|
||||||
|
try:
|
||||||
|
root_nodes = MindMapNode.query.filter_by(parent_id=None).all()
|
||||||
|
|
||||||
|
def build_tree(node):
|
||||||
|
return {
|
||||||
|
'id': node.id,
|
||||||
|
'name': node.name,
|
||||||
|
'children': [build_tree(child) for child in node.children]
|
||||||
|
}
|
||||||
|
|
||||||
|
result = [build_tree(node) for node in root_nodes]
|
||||||
|
if not result:
|
||||||
|
root = MindMapNode(name="Wissenschaft")
|
||||||
|
db.session.add(root)
|
||||||
|
db.session.commit()
|
||||||
|
result = [build_tree(root)]
|
||||||
|
|
||||||
|
return jsonify(result)
|
||||||
|
except Exception as e:
|
||||||
|
app.logger.error(f"Error in get_mindmap: {str(e)}")
|
||||||
|
return jsonify({'error': 'Fehler beim Laden der Mindmap'}), 500
|
||||||
|
|
||||||
|
@app.route('/api/thoughts/<int:node_id>', methods=['GET'])
|
||||||
|
def get_thoughts(node_id):
|
||||||
|
node = MindMapNode.query.get_or_404(node_id)
|
||||||
|
thoughts = []
|
||||||
|
|
||||||
|
for thought in node.thoughts:
|
||||||
|
thoughts.append({
|
||||||
|
'id': thought.id,
|
||||||
|
'content': thought.content,
|
||||||
|
'author': thought.author.username,
|
||||||
|
'timestamp': thought.timestamp.strftime('%d.%m.%Y, %H:%M'),
|
||||||
|
'comments_count': len(thought.comments),
|
||||||
|
'branch': thought.branch
|
||||||
|
})
|
||||||
|
|
||||||
|
return jsonify(thoughts)
|
||||||
|
|
||||||
|
@app.route('/api/thoughts', methods=['POST'])
|
||||||
|
@login_required
|
||||||
|
def add_thought():
|
||||||
|
data = request.json
|
||||||
|
node_id = data.get('node_id')
|
||||||
|
content = data.get('content')
|
||||||
|
|
||||||
|
if not node_id or not content:
|
||||||
|
return jsonify({'error': 'Fehlende Daten'}), 400
|
||||||
|
|
||||||
|
node = MindMapNode.query.get_or_404(node_id)
|
||||||
|
|
||||||
|
thought = Thought(
|
||||||
|
content=content,
|
||||||
|
branch=node.name,
|
||||||
|
user_id=current_user.id
|
||||||
|
)
|
||||||
|
|
||||||
|
db.session.add(thought)
|
||||||
|
node.thoughts.append(thought)
|
||||||
|
db.session.commit()
|
||||||
|
|
||||||
|
return jsonify({
|
||||||
|
'id': thought.id,
|
||||||
|
'content': thought.content,
|
||||||
|
'author': thought.author.username,
|
||||||
|
'timestamp': thought.timestamp.strftime('%d.%m.%Y, %H:%M'),
|
||||||
|
'branch': thought.branch
|
||||||
|
})
|
||||||
|
|
||||||
|
@app.route('/api/comments/<int:thought_id>', methods=['GET'])
|
||||||
|
def get_comments(thought_id):
|
||||||
|
thought = Thought.query.get_or_404(thought_id)
|
||||||
|
comments = [
|
||||||
|
{
|
||||||
|
'id': comment.id,
|
||||||
|
'content': comment.content,
|
||||||
|
'author': comment.author.username,
|
||||||
|
'timestamp': comment.timestamp.strftime('%d.%m.%Y, %H:%M')
|
||||||
|
}
|
||||||
|
for comment in thought.comments
|
||||||
|
]
|
||||||
|
return jsonify(comments)
|
||||||
|
|
||||||
|
@app.route('/api/comments', methods=['POST'])
|
||||||
|
@login_required
|
||||||
|
def add_comment():
|
||||||
|
data = request.json
|
||||||
|
thought_id = data.get('thought_id')
|
||||||
|
content = data.get('content')
|
||||||
|
|
||||||
|
if not thought_id or not content:
|
||||||
|
return jsonify({'error': 'Fehlende Daten'}), 400
|
||||||
|
|
||||||
|
thought = Thought.query.get_or_404(thought_id)
|
||||||
|
|
||||||
|
comment = Comment(
|
||||||
|
content=content,
|
||||||
|
thought_id=thought_id,
|
||||||
|
user_id=current_user.id
|
||||||
|
)
|
||||||
|
|
||||||
|
db.session.add(comment)
|
||||||
|
db.session.commit()
|
||||||
|
|
||||||
|
return jsonify({
|
||||||
|
'id': comment.id,
|
||||||
|
'content': comment.content,
|
||||||
|
'author': comment.author.username,
|
||||||
|
'timestamp': comment.timestamp.strftime('%d.%m.%Y, %H:%M')
|
||||||
|
})
|
||||||
|
|
||||||
|
@app.route('/admin')
|
||||||
|
@login_required
|
||||||
|
def admin():
|
||||||
|
if not current_user.is_admin:
|
||||||
|
flash('Zugriff verweigert')
|
||||||
|
return redirect(url_for('index'))
|
||||||
|
|
||||||
|
users = User.query.all()
|
||||||
|
nodes = MindMapNode.query.all()
|
||||||
|
thoughts = Thought.query.all()
|
||||||
|
|
||||||
|
return render_template('admin.html', users=users, nodes=nodes, thoughts=thoughts)
|
||||||
|
|
||||||
|
return app
|
||||||
|
|
||||||
# Database Models
|
# Database Models
|
||||||
class User(UserMixin, db.Model):
|
class User(UserMixin, db.Model):
|
||||||
id = db.Column(db.Integer, primary_key=True)
|
id = db.Column(db.Integer, primary_key=True)
|
||||||
@@ -59,206 +275,6 @@ node_thought_association = db.Table('node_thought_association',
|
|||||||
db.Column('thought_id', db.Integer, db.ForeignKey('thought.id'), primary_key=True)
|
db.Column('thought_id', db.Integer, db.ForeignKey('thought.id'), primary_key=True)
|
||||||
)
|
)
|
||||||
|
|
||||||
@login_manager.user_loader
|
|
||||||
def load_user(id):
|
|
||||||
return User.query.get(int(id))
|
|
||||||
|
|
||||||
# Routes for authentication
|
|
||||||
@app.route('/login', methods=['GET', 'POST'])
|
|
||||||
def login():
|
|
||||||
if request.method == 'POST':
|
|
||||||
username = request.form.get('username')
|
|
||||||
password = request.form.get('password')
|
|
||||||
|
|
||||||
user = User.query.filter_by(username=username).first()
|
|
||||||
if user and user.check_password(password):
|
|
||||||
login_user(user)
|
|
||||||
next_page = request.args.get('next')
|
|
||||||
return redirect(next_page or url_for('index'))
|
|
||||||
flash('Ungültiger Benutzername oder Passwort')
|
|
||||||
return render_template('login.html')
|
|
||||||
|
|
||||||
@app.route('/register', methods=['GET', 'POST'])
|
|
||||||
def register():
|
|
||||||
if request.method == 'POST':
|
|
||||||
username = request.form.get('username')
|
|
||||||
email = request.form.get('email')
|
|
||||||
password = request.form.get('password')
|
|
||||||
|
|
||||||
if User.query.filter_by(username=username).first():
|
|
||||||
flash('Benutzername existiert bereits')
|
|
||||||
return redirect(url_for('register'))
|
|
||||||
|
|
||||||
if User.query.filter_by(email=email).first():
|
|
||||||
flash('E-Mail ist bereits registriert')
|
|
||||||
return redirect(url_for('register'))
|
|
||||||
|
|
||||||
user = User(username=username, email=email)
|
|
||||||
user.set_password(password)
|
|
||||||
db.session.add(user)
|
|
||||||
db.session.commit()
|
|
||||||
|
|
||||||
login_user(user)
|
|
||||||
return redirect(url_for('index'))
|
|
||||||
return render_template('register.html')
|
|
||||||
|
|
||||||
@app.route('/logout')
|
|
||||||
@login_required
|
|
||||||
def logout():
|
|
||||||
logout_user()
|
|
||||||
return redirect(url_for('index'))
|
|
||||||
|
|
||||||
# Route for the homepage
|
|
||||||
@app.route('/')
|
|
||||||
def index():
|
|
||||||
return render_template('index.html')
|
|
||||||
|
|
||||||
# Route for the mindmap page
|
|
||||||
@app.route('/mindmap')
|
|
||||||
def mindmap():
|
|
||||||
return render_template('mindmap.html')
|
|
||||||
|
|
||||||
# Route for user profile
|
|
||||||
@app.route('/profile')
|
|
||||||
@login_required
|
|
||||||
def profile():
|
|
||||||
thoughts = Thought.query.filter_by(user_id=current_user.id).order_by(Thought.timestamp.desc()).all()
|
|
||||||
return render_template('profile.html', thoughts=thoughts)
|
|
||||||
|
|
||||||
# API routes for mindmap and thoughts
|
|
||||||
@app.route('/api/mindmap')
|
|
||||||
def get_mindmap():
|
|
||||||
root_nodes = MindMapNode.query.filter_by(parent_id=None).all()
|
|
||||||
|
|
||||||
def build_tree(node):
|
|
||||||
return {
|
|
||||||
'id': node.id,
|
|
||||||
'name': node.name,
|
|
||||||
'children': [build_tree(child) for child in node.children]
|
|
||||||
}
|
|
||||||
|
|
||||||
result = [build_tree(node) for node in root_nodes]
|
|
||||||
return jsonify(result)
|
|
||||||
|
|
||||||
@app.route('/api/thoughts/<int:node_id>', methods=['GET'])
|
|
||||||
def get_thoughts(node_id):
|
|
||||||
node = MindMapNode.query.get_or_404(node_id)
|
|
||||||
thoughts = []
|
|
||||||
|
|
||||||
for thought in node.thoughts:
|
|
||||||
thoughts.append({
|
|
||||||
'id': thought.id,
|
|
||||||
'content': thought.content,
|
|
||||||
'author': thought.author.username,
|
|
||||||
'timestamp': thought.timestamp.strftime('%d.%m.%Y, %H:%M'),
|
|
||||||
'comments_count': len(thought.comments),
|
|
||||||
'branch': thought.branch
|
|
||||||
})
|
|
||||||
|
|
||||||
return jsonify(thoughts)
|
|
||||||
|
|
||||||
@app.route('/api/thought/<int:thought_id>', methods=['GET'])
|
|
||||||
def get_thought(thought_id):
|
|
||||||
thought = Thought.query.get_or_404(thought_id)
|
|
||||||
|
|
||||||
return jsonify({
|
|
||||||
'id': thought.id,
|
|
||||||
'content': thought.content,
|
|
||||||
'author': thought.author.username,
|
|
||||||
'timestamp': thought.timestamp.strftime('%d.%m.%Y, %H:%M'),
|
|
||||||
'branch': thought.branch,
|
|
||||||
'comments_count': len(thought.comments)
|
|
||||||
})
|
|
||||||
|
|
||||||
@app.route('/api/thoughts', methods=['POST'])
|
|
||||||
@login_required
|
|
||||||
def add_thought():
|
|
||||||
data = request.json
|
|
||||||
node_id = data.get('node_id')
|
|
||||||
content = data.get('content')
|
|
||||||
|
|
||||||
if not node_id or not content:
|
|
||||||
return jsonify({'error': 'Fehlende Daten'}), 400
|
|
||||||
|
|
||||||
node = MindMapNode.query.get_or_404(node_id)
|
|
||||||
|
|
||||||
thought = Thought(
|
|
||||||
content=content,
|
|
||||||
branch=node.name,
|
|
||||||
user_id=current_user.id
|
|
||||||
)
|
|
||||||
|
|
||||||
db.session.add(thought)
|
|
||||||
node.thoughts.append(thought)
|
|
||||||
db.session.commit()
|
|
||||||
|
|
||||||
return jsonify({
|
|
||||||
'id': thought.id,
|
|
||||||
'content': thought.content,
|
|
||||||
'author': thought.author.username,
|
|
||||||
'timestamp': thought.timestamp.strftime('%d.%m.%Y, %H:%M'),
|
|
||||||
'branch': thought.branch
|
|
||||||
})
|
|
||||||
|
|
||||||
@app.route('/api/comments/<int:thought_id>', methods=['GET'])
|
|
||||||
def get_comments(thought_id):
|
|
||||||
thought = Thought.query.get_or_404(thought_id)
|
|
||||||
comments = [
|
|
||||||
{
|
|
||||||
'id': comment.id,
|
|
||||||
'content': comment.content,
|
|
||||||
'author': comment.author.username,
|
|
||||||
'timestamp': comment.timestamp.strftime('%d.%m.%Y, %H:%M')
|
|
||||||
}
|
|
||||||
for comment in thought.comments
|
|
||||||
]
|
|
||||||
return jsonify(comments)
|
|
||||||
|
|
||||||
@app.route('/api/comments', methods=['POST'])
|
|
||||||
@login_required
|
|
||||||
def add_comment():
|
|
||||||
data = request.json
|
|
||||||
thought_id = data.get('thought_id')
|
|
||||||
content = data.get('content')
|
|
||||||
|
|
||||||
if not thought_id or not content:
|
|
||||||
return jsonify({'error': 'Fehlende Daten'}), 400
|
|
||||||
|
|
||||||
thought = Thought.query.get_or_404(thought_id)
|
|
||||||
|
|
||||||
comment = Comment(
|
|
||||||
content=content,
|
|
||||||
thought_id=thought_id,
|
|
||||||
user_id=current_user.id
|
|
||||||
)
|
|
||||||
|
|
||||||
db.session.add(comment)
|
|
||||||
db.session.commit()
|
|
||||||
|
|
||||||
return jsonify({
|
|
||||||
'id': comment.id,
|
|
||||||
'content': comment.content,
|
|
||||||
'author': comment.author.username,
|
|
||||||
'timestamp': comment.timestamp.strftime('%d.%m.%Y, %H:%M')
|
|
||||||
})
|
|
||||||
|
|
||||||
# Admin routes
|
|
||||||
@app.route('/admin')
|
|
||||||
@login_required
|
|
||||||
def admin():
|
|
||||||
if not current_user.is_admin:
|
|
||||||
flash('Zugriff verweigert')
|
|
||||||
return redirect(url_for('index'))
|
|
||||||
|
|
||||||
users = User.query.all()
|
|
||||||
nodes = MindMapNode.query.all()
|
|
||||||
thoughts = Thought.query.all()
|
|
||||||
|
|
||||||
return render_template('admin.html', users=users, nodes=nodes, thoughts=thoughts)
|
|
||||||
|
|
||||||
# Flask starten
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
with app.app_context():
|
app = create_app()
|
||||||
# Make sure tables exist
|
app.run(host="0.0.0.0", port=5000, debug=True)
|
||||||
db.create_all()
|
|
||||||
app.run(host="0.0.0.0", debug=True)
|
|
||||||
@@ -1,88 +1,144 @@
|
|||||||
from app import app, db, User, MindMapNode
|
import os
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
import shutil
|
||||||
|
|
||||||
def init_database():
|
# Pfade zu möglichen Datenbankdateien
|
||||||
"""Initialize the database with admin user and mindmap structure."""
|
db_paths = [
|
||||||
with app.app_context():
|
Path("instance/mindmap.db"),
|
||||||
# Create all tables
|
Path("mindmap.db"),
|
||||||
db.create_all()
|
Path("website/instance/mindmap.db"),
|
||||||
|
Path("website/mindmap.db")
|
||||||
# Check if we already have users
|
]
|
||||||
if User.query.first() is None:
|
|
||||||
print("Creating admin user...")
|
|
||||||
# Create admin user
|
|
||||||
admin = User(username='admin', email='admin@example.com', is_admin=True)
|
|
||||||
admin.set_password('admin123')
|
|
||||||
db.session.add(admin)
|
|
||||||
|
|
||||||
# Create regular test user
|
|
||||||
test_user = User(username='test', email='test@example.com', is_admin=False)
|
|
||||||
test_user.set_password('test123')
|
|
||||||
db.session.add(test_user)
|
|
||||||
|
|
||||||
db.session.commit()
|
|
||||||
print("Admin user created successfully!")
|
|
||||||
|
|
||||||
# Check if we already have mindmap nodes
|
|
||||||
if MindMapNode.query.first() is None:
|
|
||||||
print("Creating initial mindmap structure...")
|
|
||||||
# Create initial mindmap structure
|
|
||||||
root = MindMapNode(name="Wissenschaftliche Mindmap")
|
|
||||||
db.session.add(root)
|
|
||||||
|
|
||||||
# Level 1 nodes
|
|
||||||
node1 = MindMapNode(name="Naturwissenschaften", parent=root)
|
|
||||||
node2 = MindMapNode(name="Geisteswissenschaften", parent=root)
|
|
||||||
node3 = MindMapNode(name="Technologie", parent=root)
|
|
||||||
node4 = MindMapNode(name="Künste", parent=root)
|
|
||||||
db.session.add_all([node1, node2, node3, node4])
|
|
||||||
|
|
||||||
# Level 2 nodes - Naturwissenschaften
|
|
||||||
node1_1 = MindMapNode(name="Physik", parent=node1)
|
|
||||||
node1_2 = MindMapNode(name="Biologie", parent=node1)
|
|
||||||
node1_3 = MindMapNode(name="Chemie", parent=node1)
|
|
||||||
node1_4 = MindMapNode(name="Astronomie", parent=node1)
|
|
||||||
db.session.add_all([node1_1, node1_2, node1_3, node1_4])
|
|
||||||
|
|
||||||
# Level 2 nodes - Geisteswissenschaften
|
|
||||||
node2_1 = MindMapNode(name="Philosophie", parent=node2)
|
|
||||||
node2_2 = MindMapNode(name="Geschichte", parent=node2)
|
|
||||||
node2_3 = MindMapNode(name="Psychologie", parent=node2)
|
|
||||||
node2_4 = MindMapNode(name="Soziologie", parent=node2)
|
|
||||||
db.session.add_all([node2_1, node2_2, node2_3, node2_4])
|
|
||||||
|
|
||||||
# Level 2 nodes - Technologie
|
|
||||||
node3_1 = MindMapNode(name="Informatik", parent=node3)
|
|
||||||
node3_2 = MindMapNode(name="Biotechnologie", parent=node3)
|
|
||||||
node3_3 = MindMapNode(name="Künstliche Intelligenz", parent=node3)
|
|
||||||
node3_4 = MindMapNode(name="Energietechnik", parent=node3)
|
|
||||||
db.session.add_all([node3_1, node3_2, node3_3, node3_4])
|
|
||||||
|
|
||||||
# Level 2 nodes - Künste
|
|
||||||
node4_1 = MindMapNode(name="Bildende Kunst", parent=node4)
|
|
||||||
node4_2 = MindMapNode(name="Musik", parent=node4)
|
|
||||||
node4_3 = MindMapNode(name="Literatur", parent=node4)
|
|
||||||
node4_4 = MindMapNode(name="Film", parent=node4)
|
|
||||||
db.session.add_all([node4_1, node4_2, node4_3, node4_4])
|
|
||||||
|
|
||||||
# Level 3 nodes - a few examples
|
|
||||||
# Physik
|
|
||||||
MindMapNode(name="Quantenphysik", parent=node1_1)
|
|
||||||
MindMapNode(name="Relativitätstheorie", parent=node1_1)
|
|
||||||
|
|
||||||
# Informatik
|
|
||||||
MindMapNode(name="Maschinelles Lernen", parent=node3_1)
|
|
||||||
MindMapNode(name="Softwareentwicklung", parent=node3_1)
|
|
||||||
MindMapNode(name="Datenbanken", parent=node3_1)
|
|
||||||
|
|
||||||
# Commit changes
|
|
||||||
db.session.commit()
|
|
||||||
print("Mindmap structure created successfully!")
|
|
||||||
|
|
||||||
print("Database initialization complete.")
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
# Lösche bestehende Datenbankdateien
|
||||||
init_database()
|
for db_path in db_paths:
|
||||||
print("You can now run the application with 'python app.py'")
|
if db_path.exists():
|
||||||
print("Login with:")
|
try:
|
||||||
print(" Admin: username=admin, password=admin123")
|
print(f"Lösche Datenbank: {db_path}")
|
||||||
print(" User: username=test, password=test123")
|
os.remove(db_path)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Fehler beim Löschen von {db_path}: {e}")
|
||||||
|
|
||||||
|
# Stelle sicher, dass das instance-Verzeichnis existiert
|
||||||
|
instance_dir = Path("instance")
|
||||||
|
if not instance_dir.exists():
|
||||||
|
os.makedirs(instance_dir)
|
||||||
|
|
||||||
|
# Importiere Datenbankmodelle und erstelle die Datenbank
|
||||||
|
from app import db, create_app, User, MindMapNode, Thought, Comment
|
||||||
|
|
||||||
|
app = create_app()
|
||||||
|
|
||||||
|
with app.app_context():
|
||||||
|
print("Erstelle neue Datenbank...")
|
||||||
|
db.drop_all() # Stelle sicher, dass alle Tabellen gelöscht sind
|
||||||
|
db.create_all() # Erstelle Tabellen basierend auf den Modellen
|
||||||
|
|
||||||
|
# Erstelle einen Admin-Benutzer
|
||||||
|
admin = User(username="admin", email="admin@example.com", is_admin=True)
|
||||||
|
admin.set_password("admin123")
|
||||||
|
db.session.add(admin)
|
||||||
|
|
||||||
|
# Erstelle Root-Node
|
||||||
|
root = MindMapNode(name="Wissenschaft")
|
||||||
|
db.session.add(root)
|
||||||
|
|
||||||
|
# Hauptkategorien erstellen
|
||||||
|
naturwissenschaften = MindMapNode(name="Naturwissenschaften", parent=root)
|
||||||
|
geisteswissenschaften = MindMapNode(name="Geisteswissenschaften", parent=root)
|
||||||
|
sozialwissenschaften = MindMapNode(name="Sozialwissenschaften", parent=root)
|
||||||
|
ingenieurwissenschaften = MindMapNode(name="Ingenieurwissenschaften", parent=root)
|
||||||
|
medizin = MindMapNode(name="Medizin", parent=root)
|
||||||
|
informatik = MindMapNode(name="Informatik", parent=root)
|
||||||
|
|
||||||
|
db.session.add_all([naturwissenschaften, geisteswissenschaften, sozialwissenschaften,
|
||||||
|
ingenieurwissenschaften, medizin, informatik])
|
||||||
|
|
||||||
|
# Unterkategorien für Naturwissenschaften
|
||||||
|
physik = MindMapNode(name="Physik", parent=naturwissenschaften)
|
||||||
|
chemie = MindMapNode(name="Chemie", parent=naturwissenschaften)
|
||||||
|
biologie = MindMapNode(name="Biologie", parent=naturwissenschaften)
|
||||||
|
astronomie = MindMapNode(name="Astronomie", parent=naturwissenschaften)
|
||||||
|
geologie = MindMapNode(name="Geologie", parent=naturwissenschaften)
|
||||||
|
|
||||||
|
# Unterkategorien für Physik
|
||||||
|
quantenphysik = MindMapNode(name="Quantenphysik", parent=physik)
|
||||||
|
relativitätstheorie = MindMapNode(name="Relativitätstheorie", parent=physik)
|
||||||
|
thermodynamik = MindMapNode(name="Thermodynamik", parent=physik)
|
||||||
|
|
||||||
|
# Unterkategorien für Geisteswissenschaften
|
||||||
|
philosophie = MindMapNode(name="Philosophie", parent=geisteswissenschaften)
|
||||||
|
geschichte = MindMapNode(name="Geschichte", parent=geisteswissenschaften)
|
||||||
|
linguistik = MindMapNode(name="Linguistik", parent=geisteswissenschaften)
|
||||||
|
literaturwissenschaft = MindMapNode(name="Literaturwissenschaft", parent=geisteswissenschaften)
|
||||||
|
religionswissenschaft = MindMapNode(name="Religionswissenschaft", parent=geisteswissenschaften)
|
||||||
|
|
||||||
|
# Unterkategorien für Sozialwissenschaften
|
||||||
|
soziologie = MindMapNode(name="Soziologie", parent=sozialwissenschaften)
|
||||||
|
psychologie = MindMapNode(name="Psychologie", parent=sozialwissenschaften)
|
||||||
|
politikwissenschaft = MindMapNode(name="Politikwissenschaft", parent=sozialwissenschaften)
|
||||||
|
wirtschaftswissenschaften = MindMapNode(name="Wirtschaftswissenschaften", parent=sozialwissenschaften)
|
||||||
|
|
||||||
|
# Unterkategorien für Ingenieurwissenschaften
|
||||||
|
maschinenbau = MindMapNode(name="Maschinenbau", parent=ingenieurwissenschaften)
|
||||||
|
elektrotechnik = MindMapNode(name="Elektrotechnik", parent=ingenieurwissenschaften)
|
||||||
|
bauingenieurwesen = MindMapNode(name="Bauingenieurwesen", parent=ingenieurwissenschaften)
|
||||||
|
verfahrenstechnik = MindMapNode(name="Verfahrenstechnik", parent=ingenieurwissenschaften)
|
||||||
|
|
||||||
|
# Unterkategorien für Medizin
|
||||||
|
humanmedizin = MindMapNode(name="Humanmedizin", parent=medizin)
|
||||||
|
zahnmedizin = MindMapNode(name="Zahnmedizin", parent=medizin)
|
||||||
|
pharmazie = MindMapNode(name="Pharmazie", parent=medizin)
|
||||||
|
neurologie = MindMapNode(name="Neurologie", parent=medizin)
|
||||||
|
onkologie = MindMapNode(name="Onkologie", parent=medizin)
|
||||||
|
|
||||||
|
# Unterkategorien für Informatik
|
||||||
|
künstliche_intelligenz = MindMapNode(name="Künstliche Intelligenz", parent=informatik)
|
||||||
|
datenbanken = MindMapNode(name="Datenbanken", parent=informatik)
|
||||||
|
softwareentwicklung = MindMapNode(name="Softwareentwicklung", parent=informatik)
|
||||||
|
computergrafik = MindMapNode(name="Computergrafik", parent=informatik)
|
||||||
|
cybersicherheit = MindMapNode(name="Cybersicherheit", parent=informatik)
|
||||||
|
|
||||||
|
# Alle Nodes zur Session hinzufügen
|
||||||
|
all_nodes = [physik, chemie, biologie, astronomie, geologie,
|
||||||
|
quantenphysik, relativitätstheorie, thermodynamik,
|
||||||
|
philosophie, geschichte, linguistik, literaturwissenschaft, religionswissenschaft,
|
||||||
|
soziologie, psychologie, politikwissenschaft, wirtschaftswissenschaften,
|
||||||
|
maschinenbau, elektrotechnik, bauingenieurwesen, verfahrenstechnik,
|
||||||
|
humanmedizin, zahnmedizin, pharmazie, neurologie, onkologie,
|
||||||
|
künstliche_intelligenz, datenbanken, softwareentwicklung, computergrafik, cybersicherheit]
|
||||||
|
|
||||||
|
db.session.add_all(all_nodes)
|
||||||
|
|
||||||
|
# Füge einen Beispiel-Gedanken hinzu
|
||||||
|
thought = Thought(
|
||||||
|
content="Dies ist ein Beispiel-Gedanke zur Wissenschaft allgemein.",
|
||||||
|
branch="Wissenschaft",
|
||||||
|
user_id=1 # Admin-Benutzer
|
||||||
|
)
|
||||||
|
db.session.add(thought)
|
||||||
|
root.thoughts.append(thought)
|
||||||
|
|
||||||
|
# Füge weitere Beispiel-Gedanken hinzu
|
||||||
|
thought_ai = Thought(
|
||||||
|
content="Künstliche Intelligenz transformiert viele Bereiche der Wissenschaft und Gesellschaft.",
|
||||||
|
branch="Künstliche Intelligenz",
|
||||||
|
user_id=1
|
||||||
|
)
|
||||||
|
db.session.add(thought_ai)
|
||||||
|
künstliche_intelligenz.thoughts.append(thought_ai)
|
||||||
|
|
||||||
|
thought_physik = Thought(
|
||||||
|
content="Die Quantenphysik stellt unser Verständnis der Realität grundlegend in Frage.",
|
||||||
|
branch="Quantenphysik",
|
||||||
|
user_id=1
|
||||||
|
)
|
||||||
|
db.session.add(thought_physik)
|
||||||
|
quantenphysik.thoughts.append(thought_physik)
|
||||||
|
|
||||||
|
db.session.commit()
|
||||||
|
|
||||||
|
print("Datenbank wurde erfolgreich initialisiert!")
|
||||||
|
print(f"Admin-Benutzer erstellt: admin/admin123")
|
||||||
|
print(f"Root-Node 'Wissenschaft' erstellt mit mehreren Hauptkategorien und Unterkategorien")
|
||||||
Binary file not shown.
@@ -1,11 +1,20 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
import os
|
import os
|
||||||
from init_db import init_database
|
import sys
|
||||||
from app import app
|
import logging
|
||||||
|
from app import create_app
|
||||||
|
|
||||||
|
# Configure logging
|
||||||
|
logging.basicConfig(level=logging.DEBUG)
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
app = create_app()
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
# Initialize the database first
|
logger.info("Starting Flask server on http://127.0.0.1:5000")
|
||||||
init_database()
|
try:
|
||||||
|
# Use threaded=True for better request handling
|
||||||
# Run the Flask application
|
app.run(host="127.0.0.1", port=5000, debug=True, use_reloader=False, threaded=True)
|
||||||
app.run(host="0.0.0.0", debug=True)
|
except Exception as e:
|
||||||
|
logger.error(f"Error starting Flask server: {e}")
|
||||||
|
sys.exit(1)
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
<div class="flex flex-col space-y-4 sm:flex-row sm:space-y-0 sm:space-x-4 justify-center">
|
<div class="flex flex-col space-y-4 sm:flex-row sm:space-y-0 sm:space-x-4 justify-center">
|
||||||
<a href="{{ url_for('mindmap') }}" class="bg-gradient-to-r from-indigo-500 to-purple-600 hover:from-indigo-600 hover:to-purple-700 text-white font-semibold px-6 py-3 rounded-lg transition-all duration-300 transform hover:scale-105">
|
<a href="{{ url_for('mindmap') }}" class="bg-gradient-to-r from-indigo-500 to-purple-600 hover:from-indigo-600 hover:to-purple-700 text-white font-semibold px-6 py-3 rounded-lg transition-all duration-300 transform hover:scale-105">
|
||||||
Starte die Mindmap
|
Zum Netzwerk
|
||||||
</a>
|
</a>
|
||||||
{% if not current_user.is_authenticated %}
|
{% if not current_user.is_authenticated %}
|
||||||
<a href="{{ url_for('register') }}" class="glass hover:bg-white/20 text-white font-semibold px-6 py-3 rounded-lg transition-all duration-300 transform hover:scale-105">
|
<a href="{{ url_for('register') }}" class="glass hover:bg-white/20 text-white font-semibold px-6 py-3 rounded-lg transition-all duration-300 transform hover:scale-105">
|
||||||
@@ -20,19 +20,16 @@
|
|||||||
|
|
||||||
<div class="mt-12 grid grid-cols-1 md:grid-cols-3 gap-6 w-full max-w-4xl">
|
<div class="mt-12 grid grid-cols-1 md:grid-cols-3 gap-6 w-full max-w-4xl">
|
||||||
<div class="glass p-6 text-white">
|
<div class="glass p-6 text-white">
|
||||||
<div class="text-3xl mb-2">🧠</div>
|
|
||||||
<h3 class="text-xl font-semibold mb-2">Visualisiere Wissen</h3>
|
<h3 class="text-xl font-semibold mb-2">Visualisiere Wissen</h3>
|
||||||
<p class="text-white/80">Erkenne Zusammenhänge zwischen verschiedenen Wissensgebieten durch intuitive Mindmaps.</p>
|
<p class="text-white/80">Erkenne Zusammenhänge zwischen verschiedenen Wissensgebieten durch intuitive Mindmaps.</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="glass p-6 text-white">
|
<div class="glass p-6 text-white">
|
||||||
<div class="text-3xl mb-2">💡</div>
|
|
||||||
<h3 class="text-xl font-semibold mb-2">Teile Gedanken</h3>
|
<h3 class="text-xl font-semibold mb-2">Teile Gedanken</h3>
|
||||||
<p class="text-white/80">Füge deine eigenen Gedanken zu bestehenden Themen hinzu und bereichere die Community.</p>
|
<p class="text-white/80">Füge deine eigenen Gedanken zu bestehenden Themen hinzu und bereichere die Community.</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="glass p-6 text-white">
|
<div class="glass p-6 text-white">
|
||||||
<div class="text-3xl mb-2">🔄</div>
|
|
||||||
<h3 class="text-xl font-semibold mb-2">Interaktive Vernetzung</h3>
|
<h3 class="text-xl font-semibold mb-2">Interaktive Vernetzung</h3>
|
||||||
<p class="text-white/80">Beteilige dich an Diskussionen und sieh wie sich Ideen gemeinsam entwickeln.</p>
|
<p class="text-white/80">Beteilige dich an Diskussionen und sieh wie sich Ideen gemeinsam entwickeln.</p>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -99,6 +99,13 @@
|
|||||||
.node:hover circle {
|
.node:hover circle {
|
||||||
filter: drop-shadow(0 0 8px rgba(255, 255, 255, 0.8));
|
filter: drop-shadow(0 0 8px rgba(255, 255, 255, 0.8));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Fix for "keine Auswahl" text */
|
||||||
|
#selected-node-title {
|
||||||
|
width: 100%;
|
||||||
|
overflow: visible;
|
||||||
|
word-wrap: break-word;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
@@ -346,12 +353,21 @@
|
|||||||
// Create hierarchical layout
|
// Create hierarchical layout
|
||||||
const root = d3.hierarchy(data);
|
const root = d3.hierarchy(data);
|
||||||
|
|
||||||
// Create tree layout
|
// Create radial layout instead of tree for all-direction branches
|
||||||
const treeLayout = d3.tree()
|
const radius = Math.min(width, height) / 2 - 100;
|
||||||
.size([height - 100, width - 200])
|
|
||||||
.nodeSize([80, 200]);
|
|
||||||
|
|
||||||
treeLayout(root);
|
const radialLayout = d3.cluster()
|
||||||
|
.size([360, radius]);
|
||||||
|
|
||||||
|
radialLayout(root);
|
||||||
|
|
||||||
|
// Convert to Cartesian coordinates
|
||||||
|
root.descendants().forEach(d => {
|
||||||
|
// Convert from polar to Cartesian coordinates
|
||||||
|
const angle = (d.x - 90) / 180 * Math.PI;
|
||||||
|
d.x = d.y * Math.cos(angle);
|
||||||
|
d.y = d.y * Math.sin(angle);
|
||||||
|
});
|
||||||
|
|
||||||
// Create links
|
// Create links
|
||||||
const links = g.selectAll('.link')
|
const links = g.selectAll('.link')
|
||||||
@@ -360,10 +376,10 @@
|
|||||||
.append('path')
|
.append('path')
|
||||||
.attr('class', 'link')
|
.attr('class', 'link')
|
||||||
.attr('d', d => {
|
.attr('d', d => {
|
||||||
return `M${d.source.y},${d.source.x}
|
return `M${d.source.x},${d.source.y}
|
||||||
C${(d.source.y + d.target.y) / 2},${d.source.x}
|
C${(d.source.x + d.target.x) / 2},${(d.source.y + d.target.y) / 2}
|
||||||
${(d.source.y + d.target.y) / 2},${d.target.x}
|
${(d.source.x + d.target.x) / 2},${(d.source.y + d.target.y) / 2}
|
||||||
${d.target.y},${d.target.x}`;
|
${d.target.x},${d.target.y}`;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Create nodes
|
// Create nodes
|
||||||
@@ -375,7 +391,7 @@
|
|||||||
const categoryClass = getNodeCategory(d.data.name, rootCategories);
|
const categoryClass = getNodeCategory(d.data.name, rootCategories);
|
||||||
return `node ${categoryClass} ${d.data.id === selectedNode ? 'node--selected' : ''}`;
|
return `node ${categoryClass} ${d.data.id === selectedNode ? 'node--selected' : ''}`;
|
||||||
})
|
})
|
||||||
.attr('transform', d => `translate(${d.y},${d.x})`)
|
.attr('transform', d => `translate(${d.x},${d.y})`)
|
||||||
.on('click', (event, d) => selectNode(d.data.id, d.data.name))
|
.on('click', (event, d) => selectNode(d.data.id, d.data.name))
|
||||||
.on('mouseover', function(event, d) {
|
.on('mouseover', function(event, d) {
|
||||||
tooltip.transition()
|
tooltip.transition()
|
||||||
|
|||||||
35
website/test_app.py
Normal file
35
website/test_app.py
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
from flask import Flask
|
||||||
|
|
||||||
|
app = Flask(__name__)
|
||||||
|
|
||||||
|
@app.route('/')
|
||||||
|
def hello():
|
||||||
|
return """
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Test Seite</title>
|
||||||
|
<style>
|
||||||
|
body { font-family: Arial, sans-serif; margin: 40px; line-height: 1.6; }
|
||||||
|
.container { max-width: 800px; margin: 0 auto; padding: 20px; border: 1px solid #ddd; border-radius: 5px; }
|
||||||
|
h1 { color: #333; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<h1>Test Seite funktioniert!</h1>
|
||||||
|
<p>Wenn Sie diese Seite sehen können, funktioniert der grundlegende Flask-Server korrekt.</p>
|
||||||
|
<p>Server-Status:</p>
|
||||||
|
<ul>
|
||||||
|
<li>Flask läuft auf Port 5000</li>
|
||||||
|
<li>Keine Datenbankverbindung erforderlich</li>
|
||||||
|
<li>Keine Templates erforderlich</li>
|
||||||
|
</ul>
|
||||||
|
<p>Versuchen Sie, diese URL in verschiedenen Browsern zu öffnen.</p>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
"""
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
app.run(host='0.0.0.0', port=5000, debug=True)
|
||||||
Reference in New Issue
Block a user