modified: db.py modified: routes/journal_routes.py modified: static/css/style.css modified: static/js/main.js modified: templates/base.html modified: templates/day.html modified: templates/future.html modified: templates/index.html new file: templates/monat.html modified: templates/week.html
103 lines
3.3 KiB
Python
103 lines
3.3 KiB
Python
"""Datenbankzugriff (PyMySQL) + automatisches Schema-Init.
|
|
|
|
Verwendung:
|
|
from db import get_connection, init_db
|
|
"""
|
|
import pymysql
|
|
from pymysql.cursors import DictCursor
|
|
|
|
from config import Config
|
|
|
|
|
|
def get_connection():
|
|
"""Öffnet eine neue Verbindung zur MySQL-Datenbank."""
|
|
return pymysql.connect(
|
|
host=Config.DB_HOST,
|
|
port=Config.DB_PORT,
|
|
user=Config.DB_USER,
|
|
password=Config.DB_PASSWORD,
|
|
database=Config.DB_DATABASE,
|
|
charset="utf8mb4",
|
|
cursorclass=DictCursor,
|
|
autocommit=True,
|
|
)
|
|
|
|
|
|
SCHEMA = """
|
|
CREATE TABLE IF NOT EXISTS users (
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
username VARCHAR(100) NOT NULL UNIQUE,
|
|
email VARCHAR(255),
|
|
salt VARCHAR(128) NOT NULL,
|
|
password_hash VARCHAR(512) NOT NULL,
|
|
is_admin TINYINT(1) NOT NULL DEFAULT 0,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
|
|
|
CREATE TABLE IF NOT EXISTS notes (
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
user_id INT NOT NULL,
|
|
note_date DATE NOT NULL,
|
|
bullet_type ENUM('.', 'x', '-', '?') NOT NULL DEFAULT '-',
|
|
note_text TEXT NOT NULL,
|
|
priority TINYINT NOT NULL DEFAULT 0,
|
|
status ENUM('open', 'done', 'moved') NOT NULL DEFAULT 'open',
|
|
moved_to_date DATE NULL,
|
|
moved_to_future TINYINT(1) NOT NULL DEFAULT 0,
|
|
moved_from_date DATE NULL,
|
|
refs JSON NULL,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
CONSTRAINT fk_notes_user FOREIGN KEY (user_id)
|
|
REFERENCES users(id) ON DELETE CASCADE
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
|
|
|
CREATE TABLE IF NOT EXISTS future_log (
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
user_id INT NOT NULL,
|
|
month_date DATE NOT NULL,
|
|
note_text TEXT NOT NULL,
|
|
refs JSON NULL,
|
|
status ENUM('open', 'done') NOT NULL DEFAULT 'open',
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
CONSTRAINT fk_future_user FOREIGN KEY (user_id)
|
|
REFERENCES users(id) ON DELETE CASCADE
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
|
"""
|
|
|
|
|
|
# Spalten, die für bereits bestehende Datenbanken nachgezogen werden müssen
|
|
MIGRATIONS = [
|
|
("notes", "moved_from_date", "DATE NULL"),
|
|
("notes", "refs", "JSON NULL"),
|
|
("future_log", "refs", "JSON NULL"),
|
|
]
|
|
|
|
|
|
def _ensure_column(conn, table: str, column: str, definition: str) -> None:
|
|
"""Fügt eine Spalte hinzu, falls sie noch nicht existiert (Migration)."""
|
|
with conn.cursor() as cur:
|
|
cur.execute(
|
|
"SELECT COUNT(*) AS c FROM information_schema.COLUMNS "
|
|
"WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = %s AND COLUMN_NAME = %s",
|
|
(table, column),
|
|
)
|
|
if cur.fetchone()["c"] == 0:
|
|
cur.execute(f"ALTER TABLE {table} ADD COLUMN {column} {definition}")
|
|
|
|
|
|
def init_db():
|
|
"""Erstellt das Schema, falls es noch nicht existiert."""
|
|
conn = get_connection()
|
|
try:
|
|
with conn.cursor() as cur:
|
|
for statement in SCHEMA.split(";"):
|
|
stmt = statement.strip()
|
|
if stmt:
|
|
cur.execute(stmt)
|
|
# Migrationen für bestehende Datenbanken
|
|
for table, column, definition in MIGRATIONS:
|
|
_ensure_column(conn, table, column, definition)
|
|
finally:
|
|
conn.close()
|