release nouri 0.4.0 templates suggestions and mobile sheet
This commit is contained in:
+65
-39
@@ -8,7 +8,7 @@ from flask import Flask, current_app, g
|
||||
from flask.cli import with_appcontext
|
||||
from werkzeug.security import generate_password_hash
|
||||
|
||||
from .constants import DAYPARTS
|
||||
from .constants import DAYPARTS, DEFAULT_CATEGORIES
|
||||
|
||||
|
||||
def get_db() -> sqlite3.Connection:
|
||||
@@ -33,6 +33,14 @@ def table_columns(database: sqlite3.Connection, table_name: str) -> set[str]:
|
||||
return {row["name"] for row in rows}
|
||||
|
||||
|
||||
def table_exists(database: sqlite3.Connection, table_name: str) -> bool:
|
||||
row = database.execute(
|
||||
"SELECT name FROM sqlite_master WHERE type = 'table' AND name = ?",
|
||||
(table_name,),
|
||||
).fetchone()
|
||||
return row is not None
|
||||
|
||||
|
||||
def add_column_if_missing(database: sqlite3.Connection, table_name: str, definition: str) -> None:
|
||||
column_name = definition.split()[0]
|
||||
if column_name not in table_columns(database, table_name):
|
||||
@@ -50,31 +58,41 @@ def bootstrap_legacy_schema(database: sqlite3.Connection) -> None:
|
||||
"""
|
||||
)
|
||||
|
||||
existing_tables = {
|
||||
row["name"]
|
||||
for row in database.execute(
|
||||
"SELECT name FROM sqlite_master WHERE type = 'table'"
|
||||
).fetchall()
|
||||
}
|
||||
database.execute(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS household_categories (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
household_id INTEGER NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
sort_order INTEGER NOT NULL DEFAULT 100,
|
||||
is_active INTEGER NOT NULL DEFAULT 1,
|
||||
created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
UNIQUE (household_id, name)
|
||||
)
|
||||
"""
|
||||
)
|
||||
|
||||
if "users" in existing_tables:
|
||||
if table_exists(database, "users"):
|
||||
add_column_if_missing(database, "users", "household_id INTEGER")
|
||||
add_column_if_missing(database, "users", "email TEXT")
|
||||
add_column_if_missing(database, "users", "role TEXT NOT NULL DEFAULT 'member'")
|
||||
add_column_if_missing(database, "users", "is_active INTEGER NOT NULL DEFAULT 1")
|
||||
add_column_if_missing(database, "users", "updated_at TEXT")
|
||||
|
||||
if "items" in existing_tables:
|
||||
if table_exists(database, "items"):
|
||||
add_column_if_missing(database, "items", "household_id INTEGER")
|
||||
add_column_if_missing(database, "items", "owner_user_id INTEGER")
|
||||
add_column_if_missing(database, "items", "target_user_id INTEGER")
|
||||
add_column_if_missing(database, "items", "visibility TEXT NOT NULL DEFAULT 'shared'")
|
||||
|
||||
if "shopping_entries" in existing_tables:
|
||||
if table_exists(database, "shopping_entries"):
|
||||
add_column_if_missing(database, "shopping_entries", "household_id INTEGER")
|
||||
add_column_if_missing(database, "shopping_entries", "owner_user_id INTEGER")
|
||||
add_column_if_missing(database, "shopping_entries", "visibility TEXT NOT NULL DEFAULT 'shared'")
|
||||
add_column_if_missing(database, "shopping_entries", "needed_for_date TEXT")
|
||||
add_column_if_missing(database, "shopping_entries", "needed_for_daypart_id INTEGER")
|
||||
|
||||
if "plan_entries" in existing_tables:
|
||||
if table_exists(database, "plan_entries"):
|
||||
add_column_if_missing(database, "plan_entries", "household_id INTEGER")
|
||||
add_column_if_missing(database, "plan_entries", "owner_user_id INTEGER")
|
||||
add_column_if_missing(database, "plan_entries", "visibility TEXT NOT NULL DEFAULT 'shared'")
|
||||
@@ -91,9 +109,11 @@ def ensure_default_household(database: sqlite3.Connection) -> int:
|
||||
"INSERT INTO households (name) VALUES (?)",
|
||||
("Unser Haushalt",),
|
||||
)
|
||||
return int(
|
||||
database.execute("SELECT id FROM households ORDER BY id LIMIT 1").fetchone()["id"]
|
||||
)
|
||||
return int(database.execute("SELECT id FROM households ORDER BY id LIMIT 1").fetchone()["id"])
|
||||
|
||||
|
||||
def household_ids(database: sqlite3.Connection) -> list[int]:
|
||||
return [int(row["id"]) for row in database.execute("SELECT id FROM households ORDER BY id").fetchall()]
|
||||
|
||||
|
||||
def first_user_id(database: sqlite3.Connection) -> int | None:
|
||||
@@ -101,6 +121,18 @@ def first_user_id(database: sqlite3.Connection) -> int | None:
|
||||
return int(row["id"]) if row else None
|
||||
|
||||
|
||||
def sync_default_categories(database: sqlite3.Connection) -> None:
|
||||
for household_id in household_ids(database):
|
||||
for sort_order, name in enumerate(DEFAULT_CATEGORIES, start=10):
|
||||
database.execute(
|
||||
"""
|
||||
INSERT OR IGNORE INTO household_categories (household_id, name, sort_order, is_active)
|
||||
VALUES (?, ?, ?, 1)
|
||||
""",
|
||||
(household_id, name, sort_order),
|
||||
)
|
||||
|
||||
|
||||
def ensure_schema_upgrades(database: sqlite3.Connection) -> None:
|
||||
add_column_if_missing(database, "users", "household_id INTEGER")
|
||||
add_column_if_missing(database, "users", "email TEXT")
|
||||
@@ -113,18 +145,10 @@ def ensure_schema_upgrades(database: sqlite3.Connection) -> None:
|
||||
"UPDATE users SET household_id = ? WHERE household_id IS NULL",
|
||||
(default_household_id,),
|
||||
)
|
||||
database.execute(
|
||||
"UPDATE users SET role = 'member' WHERE role IS NULL OR role = ''",
|
||||
)
|
||||
database.execute(
|
||||
"UPDATE users SET is_active = 1 WHERE is_active IS NULL",
|
||||
)
|
||||
database.execute(
|
||||
"UPDATE users SET email = NULL WHERE TRIM(COALESCE(email, '')) = ''",
|
||||
)
|
||||
database.execute(
|
||||
"UPDATE users SET updated_at = COALESCE(updated_at, created_at, CURRENT_TIMESTAMP)"
|
||||
)
|
||||
database.execute("UPDATE users SET role = 'member' WHERE role IS NULL OR role = ''")
|
||||
database.execute("UPDATE users SET is_active = 1 WHERE is_active IS NULL")
|
||||
database.execute("UPDATE users SET email = NULL WHERE TRIM(COALESCE(email, '')) = ''")
|
||||
database.execute("UPDATE users SET updated_at = COALESCE(updated_at, created_at, CURRENT_TIMESTAMP)")
|
||||
|
||||
admin_row = database.execute(
|
||||
"SELECT id FROM users WHERE role = 'admin' AND is_active = 1 ORDER BY id LIMIT 1"
|
||||
@@ -132,16 +156,16 @@ def ensure_schema_upgrades(database: sqlite3.Connection) -> None:
|
||||
if admin_row is None:
|
||||
first_id = first_user_id(database)
|
||||
if first_id is not None:
|
||||
database.execute(
|
||||
"UPDATE users SET role = 'admin' WHERE id = ?",
|
||||
(first_id,),
|
||||
)
|
||||
database.execute("UPDATE users SET role = 'admin' WHERE id = ?", (first_id,))
|
||||
|
||||
default_owner_id = first_user_id(database)
|
||||
for table_name in ("items", "shopping_entries", "plan_entries"):
|
||||
add_column_if_missing(database, table_name, "household_id INTEGER")
|
||||
add_column_if_missing(database, table_name, "owner_user_id INTEGER")
|
||||
add_column_if_missing(database, table_name, "visibility TEXT NOT NULL DEFAULT 'shared'")
|
||||
add_column_if_missing(database, "items", "target_user_id INTEGER")
|
||||
add_column_if_missing(database, "shopping_entries", "needed_for_date TEXT")
|
||||
add_column_if_missing(database, "shopping_entries", "needed_for_daypart_id INTEGER")
|
||||
|
||||
if default_owner_id is not None:
|
||||
database.execute(
|
||||
@@ -175,15 +199,11 @@ def ensure_schema_upgrades(database: sqlite3.Connection) -> None:
|
||||
(default_household_id, default_owner_id),
|
||||
)
|
||||
else:
|
||||
database.execute(
|
||||
"UPDATE items SET visibility = 'shared' WHERE visibility IS NULL OR visibility = ''"
|
||||
)
|
||||
database.execute(
|
||||
"UPDATE shopping_entries SET visibility = 'shared' WHERE visibility IS NULL OR visibility = ''"
|
||||
)
|
||||
database.execute(
|
||||
"UPDATE plan_entries SET visibility = 'shared' WHERE visibility IS NULL OR visibility = ''"
|
||||
)
|
||||
database.execute("UPDATE items SET visibility = 'shared' WHERE visibility IS NULL OR visibility = ''")
|
||||
database.execute("UPDATE shopping_entries SET visibility = 'shared' WHERE visibility IS NULL OR visibility = ''")
|
||||
database.execute("UPDATE plan_entries SET visibility = 'shared' WHERE visibility IS NULL OR visibility = ''")
|
||||
|
||||
sync_default_categories(database)
|
||||
|
||||
database.execute(
|
||||
"""
|
||||
@@ -198,6 +218,12 @@ def ensure_schema_upgrades(database: sqlite3.Connection) -> None:
|
||||
ON items (household_id, visibility, availability_state)
|
||||
"""
|
||||
)
|
||||
database.execute(
|
||||
"""
|
||||
CREATE INDEX IF NOT EXISTS idx_items_target_user
|
||||
ON items (target_user_id)
|
||||
"""
|
||||
)
|
||||
database.execute(
|
||||
"""
|
||||
CREATE INDEX IF NOT EXISTS idx_plan_entries_household_visibility
|
||||
|
||||
Reference in New Issue
Block a user