Migrate from TinyDB to SQLite
- Replace TinyDB (JSON file) with sqlite3 for data persistence - Add schema.py: table creation + data migration from db.json - Rewrite database.py: all CRUD operations use sqlite3 directly - All data retains original IDs via migration script - Remove tinydb dependency from pyproject.toml
This commit is contained in:
parent
b060ba6bf8
commit
a8fe6ed7b3
24
app.py
24
app.py
@ -66,13 +66,13 @@ def api_register():
|
|||||||
password_hash = auth.hash_password(password)
|
password_hash = auth.hash_password(password)
|
||||||
user = database.create_user(username, password_hash)
|
user = database.create_user(username, password_hash)
|
||||||
|
|
||||||
session["user_id"] = user.doc_id
|
session["user_id"] = user["id"]
|
||||||
session["username"] = username
|
session["username"] = username
|
||||||
|
|
||||||
return jsonify({
|
return jsonify({
|
||||||
"success": True,
|
"success": True,
|
||||||
"message": "Registration successful",
|
"message": "Registration successful",
|
||||||
"user_id": user.doc_id
|
"user_id": user["id"]
|
||||||
}), 201
|
}), 201
|
||||||
|
|
||||||
|
|
||||||
@ -89,14 +89,14 @@ def api_login():
|
|||||||
if not user or not auth.check_password(password, user["password_hash"]):
|
if not user or not auth.check_password(password, user["password_hash"]):
|
||||||
return jsonify({"success": False, "message": "Invalid credentials"}), 401
|
return jsonify({"success": False, "message": "Invalid credentials"}), 401
|
||||||
|
|
||||||
session["user_id"] = user.doc_id
|
session["user_id"] = user["id"]
|
||||||
session["username"] = username
|
session["username"] = username
|
||||||
|
|
||||||
return jsonify({
|
return jsonify({
|
||||||
"success": True,
|
"success": True,
|
||||||
"message": "Login successful",
|
"message": "Login successful",
|
||||||
"user": {
|
"user": {
|
||||||
"user_id": user.doc_id,
|
"user_id": user["id"],
|
||||||
"username": user["username"],
|
"username": user["username"],
|
||||||
"role": user["role"],
|
"role": user["role"],
|
||||||
"max_goals": user["max_goals"]
|
"max_goals": user["max_goals"]
|
||||||
@ -118,7 +118,7 @@ def api_me():
|
|||||||
if not user:
|
if not user:
|
||||||
return jsonify({"success": False, "message": "User not found"}), 404
|
return jsonify({"success": False, "message": "User not found"}), 404
|
||||||
return jsonify({
|
return jsonify({
|
||||||
"user_id": user.doc_id,
|
"user_id": user["id"],
|
||||||
"username": user["username"],
|
"username": user["username"],
|
||||||
"role": user["role"],
|
"role": user["role"],
|
||||||
"max_goals": user["max_goals"]
|
"max_goals": user["max_goals"]
|
||||||
@ -133,7 +133,7 @@ def api_get_goals():
|
|||||||
result = []
|
result = []
|
||||||
for goal in goals:
|
for goal in goals:
|
||||||
goal_dict = dict(goal)
|
goal_dict = dict(goal)
|
||||||
goal_dict["id"] = goal.doc_id
|
goal_dict["id"] = goal["id"]
|
||||||
result.append(goal_dict)
|
result.append(goal_dict)
|
||||||
return jsonify(result)
|
return jsonify(result)
|
||||||
|
|
||||||
@ -157,7 +157,7 @@ def api_create_goal():
|
|||||||
}), 400
|
}), 400
|
||||||
|
|
||||||
goal = database.create_goal(user_id, title)
|
goal = database.create_goal(user_id, title)
|
||||||
return jsonify({"success": True, "goal_id": goal.doc_id}), 201
|
return jsonify({"success": True, "goal_id": goal["id"]}), 201
|
||||||
|
|
||||||
|
|
||||||
@app.route("/api/goals/<int:goal_id>", methods=["PUT"])
|
@app.route("/api/goals/<int:goal_id>", methods=["PUT"])
|
||||||
@ -221,7 +221,7 @@ def api_get_tasks():
|
|||||||
result = []
|
result = []
|
||||||
for task in tasks:
|
for task in tasks:
|
||||||
task_dict = dict(task)
|
task_dict = dict(task)
|
||||||
task_dict["id"] = task.doc_id
|
task_dict["id"] = task["id"]
|
||||||
result.append(task_dict)
|
result.append(task_dict)
|
||||||
return jsonify(result)
|
return jsonify(result)
|
||||||
|
|
||||||
@ -245,7 +245,7 @@ def api_create_task():
|
|||||||
return jsonify({"success": False, "message": "Cannot add task to deactivated goal"}), 400
|
return jsonify({"success": False, "message": "Cannot add task to deactivated goal"}), 400
|
||||||
|
|
||||||
task = database.create_task(goal_id, title, desc)
|
task = database.create_task(goal_id, title, desc)
|
||||||
return jsonify({"success": True, "task_id": task.doc_id}), 201
|
return jsonify({"success": True, "task_id": task["id"]}), 201
|
||||||
|
|
||||||
|
|
||||||
@app.route("/api/tasks/<int:task_id>", methods=["PUT"])
|
@app.route("/api/tasks/<int:task_id>", methods=["PUT"])
|
||||||
@ -313,11 +313,11 @@ def api_update_task_status(task_id):
|
|||||||
doing_task = None
|
doing_task = None
|
||||||
all_tasks = database.get_tasks_by_goal(task["goal_id"])
|
all_tasks = database.get_tasks_by_goal(task["goal_id"])
|
||||||
for t in all_tasks:
|
for t in all_tasks:
|
||||||
if t.get("status") == "doing" and t.doc_id != task.doc_id:
|
if t.get("status") == "doing" and t["id"] != task["id"]:
|
||||||
doing_task = t
|
doing_task = t
|
||||||
break
|
break
|
||||||
if doing_task:
|
if doing_task:
|
||||||
database.update_task(doing_task.doc_id, status="todo")
|
database.update_task(doing_task["id"], status="todo")
|
||||||
updates["start_time"] = datetime.now().isoformat()
|
updates["start_time"] = datetime.now().isoformat()
|
||||||
else:
|
else:
|
||||||
updates["start_time"] = None
|
updates["start_time"] = None
|
||||||
@ -359,7 +359,7 @@ def api_get_users():
|
|||||||
result = []
|
result = []
|
||||||
for user in users:
|
for user in users:
|
||||||
result.append({
|
result.append({
|
||||||
"user_id": user.doc_id,
|
"user_id": user["id"],
|
||||||
"username": user["username"],
|
"username": user["username"],
|
||||||
"role": user["role"],
|
"role": user["role"],
|
||||||
"max_goals": user["max_goals"]
|
"max_goals": user["max_goals"]
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import os
|
import os
|
||||||
|
|
||||||
DB_PATH = os.path.join(os.path.dirname(__file__), "data", "db.json")
|
DB_PATH = os.path.join(os.path.dirname(__file__), "data", "db.sqlite")
|
||||||
|
|
||||||
DEFAULT_ADMIN_USERNAME = "admin"
|
DEFAULT_ADMIN_USERNAME = "admin"
|
||||||
DEFAULT_ADMIN_PASSWORD = "admin123"
|
DEFAULT_ADMIN_PASSWORD = "admin123"
|
||||||
|
|||||||
236
database.py
236
database.py
@ -1,137 +1,219 @@
|
|||||||
import os
|
from schema import get_connection
|
||||||
from tinydb import TinyDB, Query
|
|
||||||
from tinydb.operations import increment
|
|
||||||
import config
|
|
||||||
|
|
||||||
os.makedirs(os.path.dirname(config.DB_PATH), exist_ok=True)
|
|
||||||
|
|
||||||
db = TinyDB(config.DB_PATH)
|
def row_to_dict(row):
|
||||||
|
if row is None:
|
||||||
users_table = db.table("users")
|
return None
|
||||||
goals_table = db.table("goals")
|
return dict(row)
|
||||||
tasks_table = db.table("tasks")
|
|
||||||
|
|
||||||
User = Query()
|
|
||||||
Goal = Query()
|
|
||||||
Task = Query()
|
|
||||||
|
|
||||||
|
|
||||||
def init_db():
|
def init_db():
|
||||||
if users_table.count(User.role == "admin") == 0:
|
from schema import init_db as _init_db, migrate_from_tinydb
|
||||||
import bcrypt
|
_init_db()
|
||||||
password_hash = bcrypt.hashpw(
|
migrate_from_tinydb()
|
||||||
config.DEFAULT_ADMIN_PASSWORD.encode("utf-8"),
|
|
||||||
bcrypt.gensalt()
|
|
||||||
).decode("utf-8")
|
|
||||||
users_table.insert({
|
|
||||||
"username": config.DEFAULT_ADMIN_USERNAME,
|
|
||||||
"password_hash": password_hash,
|
|
||||||
"role": "admin",
|
|
||||||
"max_goals": 100
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
def get_user_by_username(username):
|
def get_user_by_username(username):
|
||||||
result = users_table.search(User.username == username)
|
conn = get_connection()
|
||||||
return result[0] if result else None
|
try:
|
||||||
|
cur = conn.execute("SELECT * FROM users WHERE username = ?", (username,))
|
||||||
|
return row_to_dict(cur.fetchone())
|
||||||
|
finally:
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
def get_user_by_id(user_id):
|
def get_user_by_id(user_id):
|
||||||
return users_table.get(doc_id=user_id)
|
conn = get_connection()
|
||||||
|
try:
|
||||||
|
cur = conn.execute("SELECT * FROM users WHERE id = ?", (user_id,))
|
||||||
|
return row_to_dict(cur.fetchone())
|
||||||
|
finally:
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
def create_user(username, password_hash, role="user", max_goals=None):
|
def create_user(username, password_hash, role="user", max_goals=None):
|
||||||
if max_goals is None:
|
if max_goals is None:
|
||||||
max_goals = config.DEFAULT_MAX_GOALS
|
max_goals = 5
|
||||||
doc_id = users_table.insert({
|
conn = get_connection()
|
||||||
"username": username,
|
try:
|
||||||
"password_hash": password_hash,
|
cur = conn.execute(
|
||||||
"role": role,
|
"INSERT INTO users (username, password_hash, role, max_goals) VALUES (?, ?, ?, ?)",
|
||||||
"max_goals": max_goals
|
(username, password_hash, role, max_goals)
|
||||||
})
|
)
|
||||||
return users_table.get(doc_id=doc_id)
|
conn.commit()
|
||||||
|
return row_to_dict(conn.execute("SELECT * FROM users WHERE id = ?", (cur.lastrowid,)).fetchone())
|
||||||
|
finally:
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
def update_user(user_id, **kwargs):
|
def update_user(user_id, **kwargs):
|
||||||
users_table.update(kwargs, doc_ids=[user_id])
|
if not kwargs:
|
||||||
|
return
|
||||||
|
sets = ", ".join(f"{k} = ?" for k in kwargs)
|
||||||
|
values = list(kwargs.values()) + [user_id]
|
||||||
|
conn = get_connection()
|
||||||
|
try:
|
||||||
|
conn.execute(f"UPDATE users SET {sets} WHERE id = ?", values)
|
||||||
|
conn.commit()
|
||||||
|
finally:
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
def get_all_users():
|
def get_all_users():
|
||||||
return users_table.all()
|
conn = get_connection()
|
||||||
|
try:
|
||||||
|
cur = conn.execute("SELECT * FROM users")
|
||||||
|
return [row_to_dict(r) for r in cur.fetchall()]
|
||||||
|
finally:
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
def get_goals_by_user(user_id):
|
def get_goals_by_user(user_id):
|
||||||
return goals_table.search(Goal.user_id == user_id)
|
conn = get_connection()
|
||||||
|
try:
|
||||||
|
cur = conn.execute("SELECT * FROM goals WHERE user_id = ?", (user_id,))
|
||||||
|
return [row_to_dict(r) for r in cur.fetchall()]
|
||||||
|
finally:
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
def get_goal_by_id(goal_id):
|
def get_goal_by_id(goal_id):
|
||||||
return goals_table.get(doc_id=goal_id)
|
conn = get_connection()
|
||||||
|
try:
|
||||||
|
cur = conn.execute("SELECT * FROM goals WHERE id = ?", (goal_id,))
|
||||||
|
return row_to_dict(cur.fetchone())
|
||||||
|
finally:
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
def create_goal(user_id, title):
|
def create_goal(user_id, title):
|
||||||
doc_id = goals_table.insert({
|
conn = get_connection()
|
||||||
"user_id": user_id,
|
try:
|
||||||
"title": title,
|
cur = conn.execute(
|
||||||
"activated": True
|
"INSERT INTO goals (user_id, title, activated) VALUES (?, ?, 1)",
|
||||||
})
|
(user_id, title)
|
||||||
return goals_table.get(doc_id=doc_id)
|
)
|
||||||
|
conn.commit()
|
||||||
|
return row_to_dict(conn.execute("SELECT * FROM goals WHERE id = ?", (cur.lastrowid,)).fetchone())
|
||||||
|
finally:
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
def update_goal(goal_id, **kwargs):
|
def update_goal(goal_id, **kwargs):
|
||||||
goals_table.update(kwargs, doc_ids=[goal_id])
|
if not kwargs:
|
||||||
|
return
|
||||||
|
sets = ", ".join(f"{k} = ?" for k in kwargs)
|
||||||
|
values = list(kwargs.values()) + [goal_id]
|
||||||
|
conn = get_connection()
|
||||||
|
try:
|
||||||
|
conn.execute(f"UPDATE goals SET {sets} WHERE id = ?", values)
|
||||||
|
conn.commit()
|
||||||
|
finally:
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
def delete_goal(goal_id):
|
def delete_goal(goal_id):
|
||||||
tasks = tasks_table.search(Task.goal_id == goal_id)
|
conn = get_connection()
|
||||||
for task in tasks:
|
try:
|
||||||
tasks_table.remove(doc_ids=[task.doc_id])
|
conn.execute("DELETE FROM tasks WHERE goal_id = ?", (goal_id,))
|
||||||
goals_table.remove(doc_ids=[goal_id])
|
conn.execute("DELETE FROM goals WHERE id = ?", (goal_id,))
|
||||||
|
conn.commit()
|
||||||
|
finally:
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
def count_goals_by_user(user_id):
|
def count_goals_by_user(user_id):
|
||||||
return len(goals_table.search(Goal.user_id == user_id))
|
conn = get_connection()
|
||||||
|
try:
|
||||||
|
cur = conn.execute("SELECT COUNT(*) FROM goals WHERE user_id = ?", (user_id,))
|
||||||
|
return cur.fetchone()[0]
|
||||||
|
finally:
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
def get_tasks_by_goal(goal_id):
|
def get_tasks_by_goal(goal_id):
|
||||||
return tasks_table.search(Task.goal_id == goal_id)
|
conn = get_connection()
|
||||||
|
try:
|
||||||
|
cur = conn.execute("SELECT * FROM tasks WHERE goal_id = ?", (goal_id,))
|
||||||
|
return [row_to_dict(r) for r in cur.fetchall()]
|
||||||
|
finally:
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
def get_task_by_id(task_id):
|
def get_task_by_id(task_id):
|
||||||
return tasks_table.get(doc_id=task_id)
|
conn = get_connection()
|
||||||
|
try:
|
||||||
|
cur = conn.execute("SELECT * FROM tasks WHERE id = ?", (task_id,))
|
||||||
|
return row_to_dict(cur.fetchone())
|
||||||
|
finally:
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
def create_task(goal_id, title, desc="", status="todo", order=None):
|
def create_task(goal_id, title, desc="", status="todo", order=None):
|
||||||
if order is None:
|
if order is None:
|
||||||
existing_tasks = tasks_table.search(Task.goal_id == goal_id)
|
conn = get_connection()
|
||||||
unfinished = [t for t in existing_tasks if t.get("status") != "done"]
|
try:
|
||||||
order = max([t.get("order", 0) for t in unfinished], default=0) + 1.0
|
cur = conn.execute(
|
||||||
|
"""SELECT COALESCE(MAX("order"), 0) + 1.0 FROM tasks
|
||||||
doc_id = tasks_table.insert({
|
WHERE goal_id = ? AND status != 'done'""",
|
||||||
"goal_id": goal_id,
|
(goal_id,)
|
||||||
"title": title,
|
)
|
||||||
"desc": desc,
|
order = cur.fetchone()[0]
|
||||||
"status": status,
|
finally:
|
||||||
"start_time": None,
|
conn.close()
|
||||||
"finished_time": None,
|
|
||||||
"order": order
|
conn = get_connection()
|
||||||
})
|
try:
|
||||||
return tasks_table.get(doc_id=doc_id)
|
cur = conn.execute(
|
||||||
|
"""INSERT INTO tasks (goal_id, title, desc, status, start_time, finished_time, "order")
|
||||||
|
VALUES (?, ?, ?, ?, ?, ?, ?)""",
|
||||||
|
(goal_id, title, desc, status, None, None, order)
|
||||||
|
)
|
||||||
|
conn.commit()
|
||||||
|
return row_to_dict(conn.execute("SELECT * FROM tasks WHERE id = ?", (cur.lastrowid,)).fetchone())
|
||||||
|
finally:
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
def update_task(task_id, **kwargs):
|
def update_task(task_id, **kwargs):
|
||||||
tasks_table.update(kwargs, doc_ids=[task_id])
|
if not kwargs:
|
||||||
|
return
|
||||||
|
sets = ", ".join(f"{k} = ?" for k in kwargs)
|
||||||
|
values = list(kwargs.values()) + [task_id]
|
||||||
|
conn = get_connection()
|
||||||
|
try:
|
||||||
|
conn.execute(f"UPDATE tasks SET {sets} WHERE id = ?", values)
|
||||||
|
conn.commit()
|
||||||
|
finally:
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
def delete_task(task_id):
|
def delete_task(task_id):
|
||||||
tasks_table.remove(doc_ids=[task_id])
|
conn = get_connection()
|
||||||
|
try:
|
||||||
|
conn.execute("DELETE FROM tasks WHERE id = ?", (task_id,))
|
||||||
|
conn.commit()
|
||||||
|
finally:
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
def get_tasks_sorted(goal_id):
|
def get_tasks_sorted(goal_id):
|
||||||
all_tasks = tasks_table.search(Task.goal_id == goal_id)
|
conn = get_connection()
|
||||||
unfinished = [t for t in all_tasks if t.get("status") != "done"]
|
try:
|
||||||
finished = [t for t in all_tasks if t.get("status") == "done"]
|
cur = conn.execute(
|
||||||
|
"""SELECT * FROM tasks WHERE goal_id = ? AND status = 'done'
|
||||||
|
ORDER BY finished_time DESC""",
|
||||||
|
(goal_id,)
|
||||||
|
)
|
||||||
|
finished = [row_to_dict(r) for r in cur.fetchall()]
|
||||||
|
|
||||||
unfinished.sort(key=lambda t: t.get("order", 0))
|
cur = conn.execute(
|
||||||
finished.sort(key=lambda t: t.get("finished_time", ""), reverse=True)
|
"""SELECT * FROM tasks WHERE goal_id = ? AND status != 'done'
|
||||||
|
ORDER BY "order" ASC""",
|
||||||
|
(goal_id,)
|
||||||
|
)
|
||||||
|
unfinished = [row_to_dict(r) for r in cur.fetchall()]
|
||||||
|
|
||||||
return finished + unfinished
|
return finished + unfinished
|
||||||
|
finally:
|
||||||
|
conn.close()
|
||||||
|
|||||||
@ -6,5 +6,4 @@ requires-python = ">=3.13"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"bcrypt>=5.0.0",
|
"bcrypt>=5.0.0",
|
||||||
"flask>=3.1.3",
|
"flask>=3.1.3",
|
||||||
"tinydb>=4.8.2",
|
|
||||||
]
|
]
|
||||||
|
|||||||
116
schema.py
Normal file
116
schema.py
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
import sqlite3
|
||||||
|
import os
|
||||||
|
import json
|
||||||
|
import config
|
||||||
|
|
||||||
|
|
||||||
|
CREATE_USERS = """
|
||||||
|
CREATE TABLE IF NOT EXISTS users (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
username TEXT NOT NULL UNIQUE,
|
||||||
|
password_hash TEXT NOT NULL,
|
||||||
|
role TEXT NOT NULL DEFAULT 'user',
|
||||||
|
max_goals INTEGER NOT NULL DEFAULT 5
|
||||||
|
)
|
||||||
|
"""
|
||||||
|
|
||||||
|
CREATE_GOALS = """
|
||||||
|
CREATE TABLE IF NOT EXISTS goals (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
user_id INTEGER NOT NULL,
|
||||||
|
title TEXT NOT NULL,
|
||||||
|
activated INTEGER NOT NULL DEFAULT 1,
|
||||||
|
FOREIGN KEY (user_id) REFERENCES users(id)
|
||||||
|
)
|
||||||
|
"""
|
||||||
|
|
||||||
|
CREATE_TASKS = """
|
||||||
|
CREATE TABLE IF NOT EXISTS tasks (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
goal_id INTEGER NOT NULL,
|
||||||
|
title TEXT NOT NULL,
|
||||||
|
desc TEXT NOT NULL DEFAULT '',
|
||||||
|
status TEXT NOT NULL DEFAULT 'todo',
|
||||||
|
start_time TEXT,
|
||||||
|
finished_time TEXT,
|
||||||
|
"order" REAL NOT NULL DEFAULT 0.0,
|
||||||
|
FOREIGN KEY (goal_id) REFERENCES goals(id)
|
||||||
|
)
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def get_connection():
|
||||||
|
os.makedirs(os.path.dirname(config.DB_PATH), exist_ok=True)
|
||||||
|
conn = sqlite3.connect(config.DB_PATH)
|
||||||
|
conn.row_factory = sqlite3.Row
|
||||||
|
conn.execute("PRAGMA foreign_keys = ON")
|
||||||
|
return conn
|
||||||
|
|
||||||
|
|
||||||
|
def init_db():
|
||||||
|
conn = get_connection()
|
||||||
|
try:
|
||||||
|
conn.execute(CREATE_USERS)
|
||||||
|
conn.execute(CREATE_GOALS)
|
||||||
|
conn.execute(CREATE_TASKS)
|
||||||
|
conn.commit()
|
||||||
|
|
||||||
|
import bcrypt
|
||||||
|
cur = conn.execute("SELECT COUNT(*) FROM users WHERE role = 'admin'")
|
||||||
|
if cur.fetchone()[0] == 0:
|
||||||
|
password_hash = bcrypt.hashpw(
|
||||||
|
config.DEFAULT_ADMIN_PASSWORD.encode("utf-8"),
|
||||||
|
bcrypt.gensalt()
|
||||||
|
).decode("utf-8")
|
||||||
|
conn.execute(
|
||||||
|
"INSERT INTO users (username, password_hash, role, max_goals) VALUES (?, ?, ?, ?)",
|
||||||
|
(config.DEFAULT_ADMIN_USERNAME, password_hash, "admin", 100)
|
||||||
|
)
|
||||||
|
conn.commit()
|
||||||
|
finally:
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
|
def migrate_from_tinydb():
|
||||||
|
json_path = os.path.join(os.path.dirname(config.DB_PATH), "db.json")
|
||||||
|
if not os.path.exists(json_path):
|
||||||
|
return
|
||||||
|
|
||||||
|
conn = get_connection()
|
||||||
|
try:
|
||||||
|
with open(json_path, "r") as f:
|
||||||
|
data = json.load(f)
|
||||||
|
|
||||||
|
if "users" in data:
|
||||||
|
for doc_id, record in data["users"].items():
|
||||||
|
record["id"] = int(doc_id)
|
||||||
|
if conn.execute("SELECT COUNT(*) FROM users WHERE id = ?", (record["id"],)).fetchone()[0] == 0:
|
||||||
|
conn.execute(
|
||||||
|
"INSERT INTO users (id, username, password_hash, role, max_goals) VALUES (?, ?, ?, ?, ?)",
|
||||||
|
(record["id"], record["username"], record["password_hash"], record["role"], record["max_goals"])
|
||||||
|
)
|
||||||
|
|
||||||
|
if "goals" in data:
|
||||||
|
for doc_id, record in data["goals"].items():
|
||||||
|
record["id"] = int(doc_id)
|
||||||
|
if conn.execute("SELECT COUNT(*) FROM goals WHERE id = ?", (record["id"],)).fetchone()[0] == 0:
|
||||||
|
conn.execute(
|
||||||
|
"INSERT INTO goals (id, user_id, title, activated) VALUES (?, ?, ?, ?)",
|
||||||
|
(record["id"], record["user_id"], record["title"], 1 if record.get("activated", True) else 0)
|
||||||
|
)
|
||||||
|
|
||||||
|
if "tasks" in data:
|
||||||
|
for doc_id, record in data["tasks"].items():
|
||||||
|
record["id"] = int(doc_id)
|
||||||
|
if conn.execute("SELECT COUNT(*) FROM tasks WHERE id = ?", (record["id"],)).fetchone()[0] == 0:
|
||||||
|
conn.execute(
|
||||||
|
"""INSERT INTO tasks (id, goal_id, title, desc, status, start_time, finished_time, "order")
|
||||||
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?)""",
|
||||||
|
(record["id"], record["goal_id"], record["title"], record.get("desc", ""),
|
||||||
|
record.get("status", "todo"), record.get("start_time"), record.get("finished_time"),
|
||||||
|
record.get("order", 0.0))
|
||||||
|
)
|
||||||
|
|
||||||
|
conn.commit()
|
||||||
|
finally:
|
||||||
|
conn.close()
|
||||||
@ -60,7 +60,7 @@ function openModal(goal = null) {
|
|||||||
|
|
||||||
if (goal) {
|
if (goal) {
|
||||||
modalTitle.textContent = "Edit Goal";
|
modalTitle.textContent = "Edit Goal";
|
||||||
goalId.value = goal.doc_id;
|
goalId.value = goal.id;
|
||||||
goalTitle.value = goal.title;
|
goalTitle.value = goal.title;
|
||||||
} else {
|
} else {
|
||||||
modalTitle.textContent = "Create Goal";
|
modalTitle.textContent = "Create Goal";
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user