Session-Daten persistent in DB speichern für Resume-Funktionalität

Problem gelöst:
- User kann nach Neustart/Beenden an derselben Stelle weitermachen
- Bei Wechsel zu Statistik und zurück gehen keine Daten verloren

Implementierung:
- Progress-Tabelle erweitert um: total_elapsed_time, key_stroke_count, is_paused
- Session-Daten werden in DB und Session gespeichert
- train() lädt Session-Daten aus DB
- update_progress speichert Session-Daten in DB
- Bei Lektionswechsel werden Session-Daten zurückgesetzt

Alembic-Migration: 8e747f72e854

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
jamulix 2025-10-29 00:33:00 +01:00
commit 6cebc245be
3 changed files with 81 additions and 12 deletions

View file

@ -0,0 +1,36 @@
"""Add session data to Progress table
Revision ID: 8e747f72e854
Revises: 1106215c45af
Create Date: 2025-10-29 00:30:27.582990
"""
from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision: str = '8e747f72e854'
down_revision: Union[str, Sequence[str], None] = '1106215c45af'
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
"""Upgrade schema."""
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('progress', sa.Column('total_elapsed_time', sa.Integer(), nullable=True, server_default='0'))
op.add_column('progress', sa.Column('key_stroke_count', sa.Integer(), nullable=True, server_default='0'))
op.add_column('progress', sa.Column('is_paused', sa.Boolean(), nullable=True, server_default='1'))
# ### end Alembic commands ###
def downgrade() -> None:
"""Downgrade schema."""
# ### commands auto generated by Alembic - please adjust! ###
op.drop_column('progress', 'is_paused')
op.drop_column('progress', 'key_stroke_count')
op.drop_column('progress', 'total_elapsed_time')
# ### end Alembic commands ###

52
app.py
View file

@ -410,14 +410,21 @@ def train():
# Lade die gespeicherte Benutzereingabe und Cursor-Position aus der Datenbank
user_input = progress.last_text
cursor_position = progress.current_position
# Lade zusätzliche Zustandsdaten aus der Session
total_elapsed_time = session.get('total_elapsed_time', 0)
net_training_time = session.get('net_training_time', 0)
key_stroke_count = session.get('key_stroke_count', 0)
# Starte immer im Pausenmodus
is_paused = True
session['is_paused'] = True
# Lade Session-Daten aus der Datenbank (für Resume nach Neustart/Statistik)
total_elapsed_time = getattr(progress, 'total_elapsed_time', 0) or 0
key_stroke_count = getattr(progress, 'key_stroke_count', 0) or 0
is_paused = getattr(progress, 'is_paused', True)
# Netto-Trainingszeit muss aus total_elapsed_time berechnet werden
# (wird in JavaScript SessionManager verwaltet)
net_training_time = total_elapsed_time
# Synchronisiere Session mit DB
session['total_elapsed_time'] = total_elapsed_time
session['net_training_time'] = net_training_time
session['key_stroke_count'] = key_stroke_count
session['is_paused'] = is_paused
return render_template('index.html',
current_text=current_text,
@ -599,10 +606,15 @@ def update_progress():
progress.current_position = cursor_position
progress.last_text = user_input
# Speichere Session-Daten auch in der DB (für Resume nach Neustart/Statistik)
progress.total_elapsed_time = int(total_elapsed_time)
progress.key_stroke_count = key_stroke_count
progress.is_paused = is_paused
# Speichere in der Datenbank
db.session.commit()
# Speichere zusätzliche Zustandsdaten in der Session
# Speichere zusätzliche Zustandsdaten auch in der Session (für Kompatibilität)
session['total_elapsed_time'] = total_elapsed_time
session['net_training_time'] = net_training_time
session['key_stroke_count'] = key_stroke_count
@ -682,13 +694,21 @@ def next_text():
else:
# Wenn wir am Ende sind, starten wir von vorne
progress.current_text_index = 0
progress.current_position = 0
progress.last_text = ""
# Setze Session-Daten zurück bei Lektionswechsel
progress.total_elapsed_time = 0
progress.key_stroke_count = 0
progress.is_paused = True
db.session.commit()
# Setze Session in Pausenmodus
# Synchronisiere Session
session['total_elapsed_time'] = 0
session['net_training_time'] = 0
session['key_stroke_count'] = 0
session['is_paused'] = True
# Bestimme den Titel der neuen Lektion
@ -728,9 +748,17 @@ def set_lesson():
progress.current_position = 0
progress.last_text = ""
# Setze Session-Daten zurück bei Lektionswechsel
progress.total_elapsed_time = 0
progress.key_stroke_count = 0
progress.is_paused = True
db.session.commit()
# Setze Session in Pausenmodus
# Synchronisiere Session
session['total_elapsed_time'] = 0
session['net_training_time'] = 0
session['key_stroke_count'] = 0
session['is_paused'] = True
# Bestimme den Titel der neuen Lektion

View file

@ -9,6 +9,11 @@ class Progress(db.Model):
current_position = db.Column(db.Integer, default=0)
last_text = db.Column(db.Text, default='')
# Session-Daten persistent speichern (für Resume nach Neustart/Statistik-Besuch)
total_elapsed_time = db.Column(db.Integer, default=0) # in Millisekunden
key_stroke_count = db.Column(db.Integer, default=0)
is_paused = db.Column(db.Boolean, default=True)
class Statistic(db.Model):
id = db.Column(db.Integer, primary_key=True)
total_chars = db.Column(db.Integer, default=0)