import os from datetime import datetime from flask import Flask, render_template, redirect, url_for, request, flash from db import get_db, init_db # ===================================================== # Constants # ===================================================== STATUS_VALUES = ("not-started", "in-progress", "done") # ===================================================== # Flask App Factory # ===================================================== def create_app(test_config: dict | None = None) -> Flask: """ Skapar och konfigurerar Flask-applikationen. Används både för runtime och tester. """ app = Flask(__name__) app.secret_key = os.environ.get("FLASK_SECRET_KEY", "dev-secret") # ------------------------------------------------- # App Configuration # ------------------------------------------------- default_db = os.path.join(os.path.dirname(__file__), "todo.db") app.config.update( DB_PATH=default_db, TESTING=False, ) if test_config: app.config.update(test_config) # ------------------------------------------------- # Initiera databasen # ------------------------------------------------- init_db(app) # ================================================= # Routes # ================================================= @app.route("/") def index(): """ Root → redirect till dashboard """ return redirect(url_for("dashboard")) @app.route("/dashboard", methods=["GET"]) def dashboard(): """ Visar alla todos """ with get_db(app) as conn: rows = conn.execute( """ SELECT * FROM todo ORDER BY CASE status WHEN 'not-started' THEN 1 WHEN 'in-progress' THEN 2 ELSE 3 END, id DESC """ ).fetchall() return render_template( "index.html", todos=rows, status_values=STATUS_VALUES, ) @app.route("/todo/create", methods=["POST"]) def create_todo(): """ Skapar en ny todo """ title = (request.form.get("title") or "").strip() description = (request.form.get("description") or "").strip() status = request.form.get("status") or "not-started" if not title or not description: flash("Title och description krävs.", "danger") return redirect(url_for("dashboard")) if status not in STATUS_VALUES: status = "not-started" now = datetime.now().isoformat(timespec="seconds") with get_db(app) as conn: conn.execute( """ INSERT INTO todo (title, description, status, created) VALUES (?, ?, ?, ?) """, (title, description, status, now), ) flash("Todo skapad!", "success") return redirect(url_for("dashboard")) @app.route("/todo//status", methods=["POST"]) def update_status(todo_id: int): """ Uppdaterar status på en todo """ status = request.form.get("status") if status not in STATUS_VALUES: flash("Ogiltig status.", "danger") return redirect(url_for("dashboard")) now = datetime.now().isoformat(timespec="seconds") with get_db(app) as conn: cur = conn.execute( """ UPDATE todo SET status = ?, edited = ? WHERE id = ? """, (status, now, todo_id), ) flash( "Status uppdaterad." if cur.rowcount else "Todo hittades inte.", "success" if cur.rowcount else "danger", ) return redirect(url_for("dashboard")) @app.route("/todo//delete", methods=["POST"]) def delete_todo(todo_id: int): """ Tar bort en todo """ with get_db(app) as conn: cur = conn.execute( "DELETE FROM todo WHERE id = ?", (todo_id,), ) flash( "Todo borttagen." if cur.rowcount else "Todo hittades inte.", "success" if cur.rowcount else "danger", ) return redirect(url_for("dashboard")) return app # ===================================================== # Main # ===================================================== if __name__ == "__main__": app = create_app() app.run(host="127.0.0.1", port=5001, debug=True)