Compare commits

...

11 Commits

Author SHA1 Message Date
fd7bc59851 Add user authentication routes: implement login, registration, and logout functionality, along with user profile and admin routes. Enhance mindmap API with error handling and default node creation. 2025-04-20 19:58:27 +01:00
55f1f87509 Refactor app initialization: encapsulate Flask app setup and database initialization within a create_app function, improving modularity and error handling during startup. 2025-04-20 19:54:07 +01:00
03f8761312 Update Docker configuration to change exposed port from 5000 to 6000 in Dockerfile and docker-compose.yml, ensuring consistency across the application. 2025-04-20 19:48:49 +01:00
506748fda7 Implement error handling and default node creation for mindmap routes; initialize database on first request to ensure root node exists. 2025-04-20 19:43:21 +01:00
6d069f68cd Update requirements.txt to include new dependencies for enhanced functionality and remove outdated packages for better compatibility. 2025-04-20 19:32:32 +01:00
4310239a7a Enhance Dockerfile: add system dependencies for building Python packages, update requirements.txt to remove specific version constraints, and verify installations with pip list. 2025-04-20 19:31:13 +01:00
e9fe907af0 Update requirements.txt to include email_validator==2.1.1 for improved email validation functionality. 2025-04-20 19:29:19 +01:00
0c69d9aba3 Remove unnecessary 'force' option from docker-compose.yml for cleaner configuration. 2025-04-20 19:26:44 +01:00
6da85cdece Refactor Docker setup: update docker-compose.yml to use a specific website directory for volumes, enable automatic restarts, and modify Dockerfile to clean up and copy application files more efficiently. 2025-04-20 19:25:08 +01:00
a073b09115 Update Docker configuration: change Docker Compose version to 3.8, enhance web service setup with context and dockerfile specifications, add volume and environment variables for Flask development, and modify Dockerfile to use Python 3.11 and improve file copying and command execution. 2025-04-20 19:22:08 +01:00
f1f4870989 Update dependencies in requirements.txt to specific versions for Flask, Flask-Login, Flask-SQLAlchemy, Werkzeug, and SQLAlchemy 2025-04-20 19:16:34 +01:00
6 changed files with 337 additions and 223 deletions

View File

@@ -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"]

View File

@@ -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

Binary file not shown.

View File

@@ -1,6 +1,6 @@
flask Flask
flask-login Flask-Login
flask-wtf Flask-SQLAlchemy
email-validator Werkzeug
python-dotenv SQLAlchemy
flask-sqlalchemy email_validator

72
start.sh Normal file
View 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

View File

@@ -6,64 +6,36 @@ 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
db = SQLAlchemy()
login_manager = LoginManager()
login_manager.login_view = 'login'
def create_app():
app = Flask(__name__) app = Flask(__name__)
app.config['SECRET_KEY'] = os.environ.get('SECRET_KEY', 'default-dev-key') app.config['SECRET_KEY'] = os.environ.get('SECRET_KEY', 'default-dev-key')
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///mindmap.db' app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///mindmap.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app) db.init_app(app)
login_manager = LoginManager(app) login_manager.init_app(app)
login_manager.login_view = 'login'
# Database Models with app.app_context():
class User(UserMixin, db.Model): # Initialize database and create root node
id = db.Column(db.Integer, primary_key=True) db.create_all()
username = db.Column(db.String(80), unique=True, nullable=False) try:
email = db.Column(db.String(120), unique=True, nullable=False) root = MindMapNode.query.filter_by(parent_id=None).first()
password_hash = db.Column(db.String(128)) if not root:
is_admin = db.Column(db.Boolean, default=False) root = MindMapNode(name="Wissenschaft")
thoughts = db.relationship('Thought', backref='author', lazy=True) db.session.add(root)
db.session.commit()
def set_password(self, password): except Exception as e:
self.password_hash = generate_password_hash(password) print(f"Error initializing database: {str(e)}")
def check_password(self, password):
return check_password_hash(self.password_hash, password)
class Thought(db.Model):
id = db.Column(db.Integer, primary_key=True)
content = db.Column(db.Text, nullable=False)
timestamp = db.Column(db.DateTime, default=datetime.utcnow)
branch = db.Column(db.String(100), nullable=False)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
comments = db.relationship('Comment', backref='thought', lazy=True, cascade="all, delete-orphan")
class Comment(db.Model):
id = db.Column(db.Integer, primary_key=True)
content = db.Column(db.Text, nullable=False)
timestamp = db.Column(db.DateTime, default=datetime.utcnow)
thought_id = db.Column(db.Integer, db.ForeignKey('thought.id'), nullable=False)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
author = db.relationship('User', backref='comments')
class MindMapNode(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(100), nullable=False)
parent_id = db.Column(db.Integer, db.ForeignKey('mind_map_node.id'), nullable=True)
children = db.relationship('MindMapNode', backref=db.backref('parent', remote_side=[id]))
thoughts = db.relationship('Thought', secondary='node_thought_association', backref='nodes')
# Association table for many-to-many relationship between MindMapNode and Thought
node_thought_association = db.Table('node_thought_association',
db.Column('node_id', db.Integer, db.ForeignKey('mind_map_node.id'), primary_key=True),
db.Column('thought_id', db.Integer, db.ForeignKey('thought.id'), primary_key=True)
)
# Register all routes with the app
@login_manager.user_loader @login_manager.user_loader
def load_user(id): def load_user(id):
return User.query.get(int(id)) return User.query.get(int(id))
# Routes for authentication
@app.route('/login', methods=['GET', 'POST']) @app.route('/login', methods=['GET', 'POST'])
def login(): def login():
if request.method == 'POST': if request.method == 'POST':
@@ -108,26 +80,32 @@ def logout():
logout_user() logout_user()
return redirect(url_for('index')) return redirect(url_for('index'))
# Route for the homepage
@app.route('/') @app.route('/')
def index(): def index():
return render_template('index.html') return render_template('index.html')
# Route for the mindmap page
@app.route('/mindmap') @app.route('/mindmap')
def 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') 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.")
# Route for user profile
@app.route('/profile') @app.route('/profile')
@login_required @login_required
def profile(): def profile():
thoughts = Thought.query.filter_by(user_id=current_user.id).order_by(Thought.timestamp.desc()).all() thoughts = Thought.query.filter_by(user_id=current_user.id).order_by(Thought.timestamp.desc()).all()
return render_template('profile.html', thoughts=thoughts) return render_template('profile.html', thoughts=thoughts)
# API routes for mindmap and thoughts
@app.route('/api/mindmap') @app.route('/api/mindmap')
def get_mindmap(): def get_mindmap():
try:
root_nodes = MindMapNode.query.filter_by(parent_id=None).all() root_nodes = MindMapNode.query.filter_by(parent_id=None).all()
def build_tree(node): def build_tree(node):
@@ -138,7 +116,16 @@ def get_mindmap():
} }
result = [build_tree(node) for node in root_nodes] 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) 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']) @app.route('/api/thoughts/<int:node_id>', methods=['GET'])
def get_thoughts(node_id): def get_thoughts(node_id):
@@ -157,19 +144,6 @@ def get_thoughts(node_id):
return jsonify(thoughts) 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']) @app.route('/api/thoughts', methods=['POST'])
@login_required @login_required
def add_thought(): def add_thought():
@@ -242,7 +216,6 @@ def add_comment():
'timestamp': comment.timestamp.strftime('%d.%m.%Y, %H:%M') 'timestamp': comment.timestamp.strftime('%d.%m.%Y, %H:%M')
}) })
# Admin routes
@app.route('/admin') @app.route('/admin')
@login_required @login_required
def admin(): def admin():
@@ -256,9 +229,52 @@ def admin():
return render_template('admin.html', users=users, nodes=nodes, thoughts=thoughts) return render_template('admin.html', users=users, nodes=nodes, thoughts=thoughts)
# Flask starten return app
# Database Models
class User(UserMixin, db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True, nullable=False)
email = db.Column(db.String(120), unique=True, nullable=False)
password_hash = db.Column(db.String(128))
is_admin = db.Column(db.Boolean, default=False)
thoughts = db.relationship('Thought', backref='author', lazy=True)
def set_password(self, password):
self.password_hash = generate_password_hash(password)
def check_password(self, password):
return check_password_hash(self.password_hash, password)
class Thought(db.Model):
id = db.Column(db.Integer, primary_key=True)
content = db.Column(db.Text, nullable=False)
timestamp = db.Column(db.DateTime, default=datetime.utcnow)
branch = db.Column(db.String(100), nullable=False)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
comments = db.relationship('Comment', backref='thought', lazy=True, cascade="all, delete-orphan")
class Comment(db.Model):
id = db.Column(db.Integer, primary_key=True)
content = db.Column(db.Text, nullable=False)
timestamp = db.Column(db.DateTime, default=datetime.utcnow)
thought_id = db.Column(db.Integer, db.ForeignKey('thought.id'), nullable=False)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
author = db.relationship('User', backref='comments')
class MindMapNode(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(100), nullable=False)
parent_id = db.Column(db.Integer, db.ForeignKey('mind_map_node.id'), nullable=True)
children = db.relationship('MindMapNode', backref=db.backref('parent', remote_side=[id]))
thoughts = db.relationship('Thought', secondary='node_thought_association', backref='nodes')
# Association table for many-to-many relationship between MindMapNode and Thought
node_thought_association = db.Table('node_thought_association',
db.Column('node_id', db.Integer, db.ForeignKey('mind_map_node.id'), primary_key=True),
db.Column('thought_id', db.Integer, db.ForeignKey('thought.id'), primary_key=True)
)
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=6000, debug=True)
db.create_all()
app.run(host="0.0.0.0", debug=True)