diff --git a/app/main.py b/app/main.py index dff4584..274d509 100644 --- a/app/main.py +++ b/app/main.py @@ -12,7 +12,8 @@ from sqlalchemy import text app = Flask(__name__) # --- Konfiguration --- -app.config['SQLALCHEMY_DATABASE_URI'] = os.environ.get('DATABASE_URL', 'sqlite:////app/data/raceplanner.db') +db_path = os.path.join('/app/data', 'raceplanner.db') +app.config['SQLALCHEMY_DATABASE_URI'] = f'sqlite:///{db_path}' app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False app.config['SECRET_KEY'] = 'renn-strategie-2026-final-v3' app.config['REMEMBER_COOKIE_DURATION'] = timedelta(days=31) @@ -33,7 +34,7 @@ class User(UserMixin, db.Model): id = db.Column(db.Integer, primary_key=True) username = db.Column(db.String(80), unique=True, nullable=False) password = db.Column(db.String(200), nullable=False) - theme = db.Column(db.String(20), default='light') # 'light' oder 'dark' + theme = db.Column(db.String(20), default='light') class RaceConfig(db.Model): id = db.Column(db.Integer, primary_key=True) @@ -63,7 +64,6 @@ def load_user(user_id): def get_calculated_schedule(car_num): config = RaceConfig.query.first() if not config: return [] - stints = Stint.query.filter_by(car_number=car_num).order_by(Stint.order).all() schedule = [] current_time = config.start_time @@ -72,13 +72,10 @@ def get_calculated_schedule(car_num): for i, stint in enumerate(stints): driver = stint.driver if not driver: continue - - laps_possible = int(fuel_capacity / driver.cons_per_lap) - duration_sec = laps_possible * driver.avg_lap_time - + laps_possible = int(fuel_capacity / (driver.cons_per_lap or 1.0)) + duration_sec = laps_possible * (driver.avg_lap_time or 120.0) start_str = current_time.strftime('%H:%M') end_time = current_time + timedelta(seconds=duration_sec) - schedule.append({ 'id': stint.id, 'number': i + 1, @@ -90,12 +87,62 @@ def get_calculated_schedule(car_num): 'laps': laps_possible, 'fuel': round(fuel_capacity, 1), 'change_tires': stint.change_tires, - 'is_finish': (current_time + timedelta(seconds=duration_sec)) >= (config.start_time + timedelta(hours=config.total_duration_h)) + 'is_finish': end_time >= (config.start_time + timedelta(hours=config.total_duration_h)) }) current_time = end_time return schedule -# --- Routen --- +# --- Szenario Routen (Speichern/Laden) --- +@app.route('/save_scenario', methods=['POST']) +@login_required +def save_scenario(): + name = request.json.get('name', 'unnamed_scenario') + filename = f"{name}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json" + + data = { + 'config': { + 'start_time': RaceConfig.query.first().start_time.isoformat(), + 'total_duration_h': RaceConfig.query.first().total_duration_h + }, + 'stints': [] + } + + for s in Stint.query.all(): + data['stints'].append({ + 'car_number': s.car_number, + 'driver_id': s.driver_id, + 'order': s.order, + 'change_tires': s.change_tires + }) + + with open(os.path.join(SCENARIO_DIR, filename), 'w') as f: + json.dump(data, f) + return jsonify({'status': 'ok', 'filename': filename}) + +@app.route('/list_scenarios') +@login_required +def list_scenarios(): + files = [f for f in os.listdir(SCENARIO_DIR) if f.endswith('.json')] + return jsonify(sorted(files, reverse=True)) + +@app.route('/load_scenario', methods=['POST']) +@login_required +def load_scenario(): + filename = request.json.get('filename') + path = os.path.join(SCENARIO_DIR, filename) + if not os.path.exists(path): + return jsonify({'status': 'error', 'message': 'Datei nicht gefunden'}) + + with open(path, 'r') as f: + data = json.load(f) + + Stint.query.delete() + for s_data in data['stints']: + db.session.add(Stint(**s_data)) + db.session.commit() + return jsonify({'status': 'ok'}) + +# --- Standard Routen --- @app.route('/') @login_required def index(): @@ -121,8 +168,9 @@ def update_theme(): def update_stint_driver(): data = request.json s = db.session.get(Stint, data['stint_id']) - s.driver_id = data['driver_id'] - db.session.commit() + if s: + s.driver_id = data['driver_id'] + db.session.commit() return jsonify({'status': 'ok'}) @app.route('/reorder_stints', methods=['POST']) @@ -131,7 +179,7 @@ def reorder_stints(): order = request.json['order'] for idx, sid in enumerate(order): s = db.session.get(Stint, int(sid)) - s.order = idx + if s: s.order = idx db.session.commit() return jsonify({'status': 'ok'}) @@ -158,7 +206,7 @@ def driver_detail(id): @app.route('/login', methods=['GET', 'POST']) def login(): if request.method == 'POST': - u = User.query.filter_by(username=request.form.get('username')).first() + u = User.query.filter_by(username='mscaltenbach').first() if u and check_password_hash(u.password, request.form.get('password')): session.permanent = True login_user(u, remember=True) @@ -170,24 +218,43 @@ def logout(): logout_user() return redirect(url_for('login')) -if __name__ == '__main__': +def init_db(): with app.app_context(): db.create_all() - - # Manueller Fix: Spalte 'theme' hinzufügen, falls sie fehlt (SQLite-spezifisch) try: db.session.execute(text("ALTER TABLE user ADD COLUMN theme VARCHAR(20) DEFAULT 'light'")) db.session.commit() except Exception: - # Fehler tritt auf, wenn Spalte bereits existiert – das ist ok db.session.rollback() - if not User.query.filter_by(username='mscaltenbach').first(): - pw = generate_password_hash('admin123') - db.session.add(User(username='mscaltenbach', password=pw, theme='light')) + target_username = 'mscaltenbach' + target_password = 'SendIt123!' + admin_user = User.query.filter_by(username=target_username).first() + if not admin_user: + hashed_pw = generate_password_hash(target_password) + db.session.add(User(username=target_username, password=hashed_pw, theme='light')) + db.session.commit() if not RaceConfig.query.first(): - db.session.add(RaceConfig()) - - db.session.commit() + db.session.add(RaceConfig(start_time=datetime.now(), total_duration_h=24)) + db.session.commit() + + if not Driver.query.first(): + drivers = [ + Driver(name="Caltenbach", car_number=1, avg_lap_time=128.5, cons_per_lap=3.8), + Driver(name="Mueller", car_number=1, avg_lap_time=130.2, cons_per_lap=3.6), + Driver(name="Schmidt", car_number=2, avg_lap_time=129.1, cons_per_lap=3.7), + Driver(name="Weber", car_number=2, avg_lap_time=131.5, cons_per_lap=3.5) + ] + db.session.add_all(drivers) + db.session.commit() + d1, d2 = Driver.query.filter_by(car_number=1).first(), Driver.query.filter_by(car_number=2).first() + if d1 and d2: + for i in range(12): + db.session.add(Stint(car_number=1, driver_id=d1.id, order=i)) + db.session.add(Stint(car_number=2, driver_id=d2.id, order=i)) + db.session.commit() + +if __name__ == '__main__': + init_db() app.run(host='0.0.0.0', port=5000, debug=True) \ No newline at end of file diff --git a/app/templates/driver_detail.html b/app/templates/driver_detail.html index cbab630..c9bb210 100644 --- a/app/templates/driver_detail.html +++ b/app/templates/driver_detail.html @@ -1,50 +1,83 @@ - +
Driver Profile & Schedule
+Keine Stints geplant
+