294 lines
12 KiB
Python
294 lines
12 KiB
Python
from database.db import get_connection
|
|
|
|
|
|
def _table_sql(cur, table_name: str) -> str:
|
|
cur.execute(
|
|
"""
|
|
SELECT sql
|
|
FROM sqlite_master
|
|
WHERE type = 'table' AND name = ?
|
|
""",
|
|
(table_name,),
|
|
)
|
|
row = cur.fetchone()
|
|
return row[0] if row and row[0] else ""
|
|
|
|
|
|
def _rebuild_table(cur, table_name: str, create_sql: str, copy_sql: str) -> None:
|
|
temp_name = f"{table_name}_new"
|
|
cur.execute(f"DROP TABLE IF EXISTS {temp_name}")
|
|
cur.execute(create_sql.format(table=temp_name))
|
|
cur.execute(copy_sql.format(table=temp_name))
|
|
cur.execute(f"DROP TABLE {table_name}")
|
|
cur.execute(f"ALTER TABLE {temp_name} RENAME TO {table_name}")
|
|
|
|
|
|
def init_db():
|
|
with get_connection() as conn:
|
|
cur = conn.cursor()
|
|
|
|
# ─── PINPAD ERRORS ───────────────────────
|
|
cur.execute("""
|
|
CREATE TABLE IF NOT EXISTS pinpad_errors (
|
|
code INTEGER PRIMARY KEY,
|
|
reason TEXT NOT NULL,
|
|
action TEXT NOT NULL
|
|
);
|
|
""")
|
|
|
|
# ─── TERMINAL INSTRUCTIONS ───────────────
|
|
cur.execute("""
|
|
CREATE TABLE IF NOT EXISTS terminal_instructions (
|
|
id INTEGER PRIMARY KEY,
|
|
title TEXT NOT NULL
|
|
);
|
|
""")
|
|
|
|
cur.execute("""
|
|
CREATE TABLE IF NOT EXISTS terminal_instruction_keys (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
instruction_id INTEGER NOT NULL,
|
|
key TEXT NOT NULL,
|
|
key_type TEXT CHECK(key_type IN ('code','text')) NOT NULL,
|
|
FOREIGN KEY (instruction_id)
|
|
REFERENCES terminal_instructions(id)
|
|
ON DELETE CASCADE
|
|
);
|
|
""")
|
|
|
|
cur.execute("""
|
|
CREATE TABLE IF NOT EXISTS terminal_instruction_steps (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
instruction_id INTEGER NOT NULL,
|
|
step_order INTEGER NOT NULL,
|
|
type TEXT CHECK(type IN ('text','image','pause','goto')) NOT NULL,
|
|
content TEXT NOT NULL,
|
|
FOREIGN KEY (instruction_id)
|
|
REFERENCES terminal_instructions(id)
|
|
ON DELETE CASCADE
|
|
);
|
|
""")
|
|
|
|
# Tech problems
|
|
cur.execute("""
|
|
CREATE TABLE IF NOT EXISTS tech_problems (
|
|
id TEXT PRIMARY KEY,
|
|
task_type TEXT CHECK(task_type IN ('ADMIN','TECH')) NOT NULL,
|
|
keywords TEXT NOT NULL
|
|
);
|
|
""")
|
|
|
|
cur.execute("""
|
|
CREATE TABLE IF NOT EXISTS tech_problem_solutions (
|
|
problem_id TEXT PRIMARY KEY,
|
|
problem_name TEXT NOT NULL,
|
|
task_type TEXT CHECK(task_type IN ('ADMIN','TECH')) NOT NULL,
|
|
can_fix_self TEXT CHECK(can_fix_self IN ('YES','NO')) NOT NULL,
|
|
need_result_feedback TEXT CHECK(need_result_feedback IN ('YES','NO')) NOT NULL,
|
|
solution_steps TEXT NOT NULL,
|
|
tools_needed TEXT NOT NULL,
|
|
when_stop_and_report TEXT NOT NULL,
|
|
FOREIGN KEY (problem_id)
|
|
REFERENCES tech_problems(id)
|
|
ON DELETE CASCADE
|
|
);
|
|
""")
|
|
|
|
cur.execute("""
|
|
CREATE TABLE IF NOT EXISTS tech_problem_progress (
|
|
user_id INTEGER PRIMARY KEY,
|
|
problem_id TEXT NOT NULL,
|
|
task_type TEXT CHECK(task_type IN ('ADMIN','TECH')) NOT NULL,
|
|
need_result_feedback TEXT CHECK(need_result_feedback IN ('YES','NO')) NOT NULL,
|
|
FOREIGN KEY (problem_id)
|
|
REFERENCES tech_problems(id)
|
|
ON DELETE CASCADE
|
|
);
|
|
""")
|
|
|
|
# Stores per-user pause progress for terminal instructions
|
|
cur.execute("""
|
|
CREATE TABLE IF NOT EXISTS instruction_progress (
|
|
user_id INTEGER PRIMARY KEY,
|
|
instruction_id INTEGER NOT NULL,
|
|
next_step INTEGER NOT NULL,
|
|
pause_at_end INTEGER NOT NULL DEFAULT 0,
|
|
FOREIGN KEY (instruction_id)
|
|
REFERENCES terminal_instructions(id)
|
|
ON DELETE CASCADE
|
|
);
|
|
""")
|
|
|
|
# Chat logs
|
|
cur.execute("""
|
|
CREATE TABLE IF NOT EXISTS message_log (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
user_id INTEGER NOT NULL,
|
|
created_at TEXT NOT NULL,
|
|
message TEXT NOT NULL
|
|
);
|
|
""")
|
|
|
|
cur.execute("""
|
|
CREATE TABLE IF NOT EXISTS event_log (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
user_id INTEGER NOT NULL,
|
|
created_at TEXT NOT NULL,
|
|
event_type TEXT NOT NULL,
|
|
event_value TEXT NOT NULL
|
|
);
|
|
""")
|
|
|
|
# Migrate terminal_instruction_steps if it doesn't allow 'pause' or 'goto'
|
|
terminal_steps_sql = _table_sql(cur, "terminal_instruction_steps")
|
|
if terminal_steps_sql and ("pause" not in terminal_steps_sql or "goto" not in terminal_steps_sql):
|
|
cur.execute("""
|
|
CREATE TABLE terminal_instruction_steps_new (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
instruction_id INTEGER NOT NULL,
|
|
step_order INTEGER NOT NULL,
|
|
type TEXT CHECK(type IN ('text','image','pause','goto')) NOT NULL,
|
|
content TEXT NOT NULL,
|
|
FOREIGN KEY (instruction_id)
|
|
REFERENCES terminal_instructions(id)
|
|
ON DELETE CASCADE
|
|
);
|
|
""")
|
|
cur.execute("""
|
|
INSERT INTO terminal_instruction_steps_new
|
|
(id, instruction_id, step_order, type, content)
|
|
SELECT id, instruction_id, step_order, type, content
|
|
FROM terminal_instruction_steps
|
|
""")
|
|
cur.execute("DROP TABLE terminal_instruction_steps")
|
|
cur.execute("ALTER TABLE terminal_instruction_steps_new RENAME TO terminal_instruction_steps")
|
|
|
|
if "FOREIGN KEY" not in _table_sql(cur, "terminal_instruction_keys").upper():
|
|
_rebuild_table(
|
|
cur,
|
|
"terminal_instruction_keys",
|
|
"""
|
|
CREATE TABLE {table} (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
instruction_id INTEGER NOT NULL,
|
|
key TEXT NOT NULL,
|
|
key_type TEXT CHECK(key_type IN ('code','text')) NOT NULL,
|
|
FOREIGN KEY (instruction_id)
|
|
REFERENCES terminal_instructions(id)
|
|
ON DELETE CASCADE
|
|
);
|
|
""",
|
|
"""
|
|
INSERT INTO {table} (id, instruction_id, key, key_type)
|
|
SELECT k.id, k.instruction_id, k.key, k.key_type
|
|
FROM terminal_instruction_keys k
|
|
JOIN terminal_instructions i ON i.id = k.instruction_id
|
|
""",
|
|
)
|
|
|
|
if "FOREIGN KEY" not in _table_sql(cur, "terminal_instruction_steps").upper():
|
|
_rebuild_table(
|
|
cur,
|
|
"terminal_instruction_steps",
|
|
"""
|
|
CREATE TABLE {table} (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
instruction_id INTEGER NOT NULL,
|
|
step_order INTEGER NOT NULL,
|
|
type TEXT CHECK(type IN ('text','image','pause','goto')) NOT NULL,
|
|
content TEXT NOT NULL,
|
|
FOREIGN KEY (instruction_id)
|
|
REFERENCES terminal_instructions(id)
|
|
ON DELETE CASCADE
|
|
);
|
|
""",
|
|
"""
|
|
INSERT INTO {table} (id, instruction_id, step_order, type, content)
|
|
SELECT s.id, s.instruction_id, s.step_order, s.type, s.content
|
|
FROM terminal_instruction_steps s
|
|
JOIN terminal_instructions i ON i.id = s.instruction_id
|
|
""",
|
|
)
|
|
|
|
if "FOREIGN KEY" not in _table_sql(cur, "tech_problem_solutions").upper():
|
|
_rebuild_table(
|
|
cur,
|
|
"tech_problem_solutions",
|
|
"""
|
|
CREATE TABLE {table} (
|
|
problem_id TEXT PRIMARY KEY,
|
|
problem_name TEXT NOT NULL,
|
|
task_type TEXT CHECK(task_type IN ('ADMIN','TECH')) NOT NULL,
|
|
can_fix_self TEXT CHECK(can_fix_self IN ('YES','NO')) NOT NULL,
|
|
need_result_feedback TEXT CHECK(need_result_feedback IN ('YES','NO')) NOT NULL,
|
|
solution_steps TEXT NOT NULL,
|
|
tools_needed TEXT NOT NULL,
|
|
when_stop_and_report TEXT NOT NULL,
|
|
FOREIGN KEY (problem_id)
|
|
REFERENCES tech_problems(id)
|
|
ON DELETE CASCADE
|
|
);
|
|
""",
|
|
"""
|
|
INSERT INTO {table}
|
|
(problem_id, problem_name, task_type, can_fix_self,
|
|
need_result_feedback, solution_steps, tools_needed,
|
|
when_stop_and_report)
|
|
SELECT s.problem_id, s.problem_name, s.task_type, s.can_fix_self,
|
|
s.need_result_feedback, s.solution_steps, s.tools_needed,
|
|
s.when_stop_and_report
|
|
FROM tech_problem_solutions s
|
|
JOIN tech_problems p ON p.id = s.problem_id
|
|
""",
|
|
)
|
|
|
|
if "FOREIGN KEY" not in _table_sql(cur, "tech_problem_progress").upper():
|
|
_rebuild_table(
|
|
cur,
|
|
"tech_problem_progress",
|
|
"""
|
|
CREATE TABLE {table} (
|
|
user_id INTEGER PRIMARY KEY,
|
|
problem_id TEXT NOT NULL,
|
|
task_type TEXT CHECK(task_type IN ('ADMIN','TECH')) NOT NULL,
|
|
need_result_feedback TEXT CHECK(need_result_feedback IN ('YES','NO')) NOT NULL,
|
|
FOREIGN KEY (problem_id)
|
|
REFERENCES tech_problems(id)
|
|
ON DELETE CASCADE
|
|
);
|
|
""",
|
|
"""
|
|
INSERT INTO {table} (user_id, problem_id, task_type, need_result_feedback)
|
|
SELECT p.user_id, p.problem_id, p.task_type, p.need_result_feedback
|
|
FROM tech_problem_progress p
|
|
JOIN tech_problems t ON t.id = p.problem_id
|
|
""",
|
|
)
|
|
|
|
if "FOREIGN KEY" not in _table_sql(cur, "instruction_progress").upper():
|
|
_rebuild_table(
|
|
cur,
|
|
"instruction_progress",
|
|
"""
|
|
CREATE TABLE {table} (
|
|
user_id INTEGER PRIMARY KEY,
|
|
instruction_id INTEGER NOT NULL,
|
|
next_step INTEGER NOT NULL,
|
|
pause_at_end INTEGER NOT NULL DEFAULT 0,
|
|
FOREIGN KEY (instruction_id)
|
|
REFERENCES terminal_instructions(id)
|
|
ON DELETE CASCADE
|
|
);
|
|
""",
|
|
"""
|
|
INSERT INTO {table} (user_id, instruction_id, next_step, pause_at_end)
|
|
SELECT p.user_id, p.instruction_id, p.next_step, p.pause_at_end
|
|
FROM instruction_progress p
|
|
JOIN terminal_instructions i ON i.id = p.instruction_id
|
|
""",
|
|
)
|
|
|
|
conn.commit()
|
|
|
|
print("✅ Database initialized")
|