diff --git a/ER.dia b/ER.dia index 987ac8d..2e41641 100644 Binary files a/ER.dia and b/ER.dia differ diff --git a/UML.dia b/UML.dia index 702bbce..fd38487 100644 Binary files a/UML.dia and b/UML.dia differ diff --git a/app.py b/app.py index 71fff9e..6bc5be6 100644 --- a/app.py +++ b/app.py @@ -323,6 +323,24 @@ def delete_habit(): return {} +@app.route('/reorder', methods=['POST']) +@login_required +def reorder_habits(): + new_index = request.get_json()["newIndex"] + habit = Habit.get(request.get_json()["habitId"]) + + if habit is None: + return {"error": "Habit not found"} + + # Check if habit belongs to user + if habit.user_id != current_user.id: + return {"error": "Habit does not belong to user"} + + habit.update_slot(new_index) + + return {} + + # Run the application if __name__ == '__main__': app.run(port=5000, debug=True) diff --git a/db/SQLiteClient.py b/db/SQLiteClient.py index d6e0481..d31ac8d 100644 --- a/db/SQLiteClient.py +++ b/db/SQLiteClient.py @@ -57,7 +57,7 @@ def update_user(id: int, name: str, email: str, password: str = None): def delete_user(id: int): - query = f"DELETE FROM habits WHERE user_id = {id};" + query = f"DELETE FROM habit_lists WHERE (SELECT list_id FROM habit_users WHERE user_id = {id}) = id;" query2 = f"DELETE FROM users WHERE id = {id};" conn = con3() cursor = conn.cursor() @@ -69,9 +69,9 @@ def delete_user(id: int): ### Habit.py ### -def create_habit(user_id: int, name: str, times: int, unit: int, slot: int, note: str | None=None): +def create_habit(list_id: int, name: str, times: int, unit: int, slot: int, note: str | None=None): now = datetime.now().isoformat() - query = (f"INSERT INTO habits (user_id, name, note, times, unit, slot, created_at, updated_at) VALUES ('{user_id}', " + query = (f"INSERT INTO habits (list_id, name, note, times, unit, slot, created_at, updated_at) VALUES ('{list_id}', " f"'{name}', '{note}', '{times}', '{unit}', '{slot}', '{now}', '{now}');") conn = con3() cursor = conn.cursor() @@ -91,8 +91,8 @@ def get_habit(id: int): return habit -def get_habits(user_id: int): - query = f"SELECT * FROM habits WHERE user_id = {user_id};" +def get_habits(list_id: int): + query = f"SELECT * FROM habits WHERE list_id = {list_id};" conn = con3() cursor = conn.cursor() cursor.execute(query) @@ -104,8 +104,8 @@ def get_habits(user_id: int): def get_heatmap_value(user_id: int, days: int): date = (datetime.now() - timedelta(days=days)).date() print(date) - query = f"SELECT id FROM habits WHERE user_id = {user_id};" - query2 = (f"SELECT habits.id FROM habits, habit_trackings WHERE habits.user_id = {user_id} " + query = f"SELECT id FROM habits WHERE (SELECT id FROM habit_lists WHERE (SELECT list_id FROM habit_users WHERE user_id = {user_id}) = id) = list_id;" + query2 = (f"SELECT habits.id FROM habits, habit_trackings WHERE (SELECT id FROM habit_lists WHERE (SELECT list_id FROM habit_users WHERE user_id = {user_id}) = id) = list_id " f"AND habits.created_at LIKE '{date}%' AND habit_trackings.habit_id = habits.id;") print(query2) conn = con3() @@ -122,8 +122,8 @@ def get_heatmap_value(user_id: int, days: int): return int(count2 / count * 100) -def get_next_slot(user_id: int): - query = f"SELECT slot FROM habits WHERE user_id = {user_id} ORDER BY slot DESC LIMIT 1;" +def get_next_slot(list_id: int): + query = f"SELECT slot FROM habits WHERE list_id = {list_id} ORDER BY slot DESC LIMIT 1;" conn = con3() cursor = conn.cursor() cursor.execute(query) @@ -132,8 +132,8 @@ def get_next_slot(user_id: int): return slot[0] + 1 if slot else 0 -def get_slots(user_id: int): - query = f"SELECT id, slot FROM habits WHERE user_id = {user_id} ORDER BY slot;" +def get_slots(list_id: int): + query = f"SELECT id, slot FROM habits WHERE list_id = {list_id} ORDER BY slot;" conn = con3() cursor = conn.cursor() cursor.execute(query) @@ -174,10 +174,10 @@ def delete_habit(id: int): ### HabitTrackings.py ### -def create_habitTrackings(habit_id: int, times: int): +def create_habitTrackings(habit_id: int): now = datetime.now().isoformat() query = ( - f"INSERT INTO habit_trackings (habit_id, times, created_at) VALUES ('{habit_id}', '{times}','{now}');") + f"INSERT INTO habit_trackings (habit_id, created_at) VALUES ('{habit_id}','{now}');") conn = con3() cursor = conn.cursor() cursor.execute(query) @@ -215,6 +215,59 @@ def delete_habitTrackings(id: int): conn.close() +### HabitList.py ### +def create_habitList(user_id: int, name: str, description: str): + now = datetime.now().isoformat() + query = ( + f"INSERT INTO habit_lists (user_id, name, description, created_at, updated_at) VALUES ('{user_id}', '{name}', '{description}', '{now}');") + conn = con3() + cursor = conn.cursor() + cursor.execute(query) + conn.commit() + conn.close() + return cursor.lastrowid + + +def get_habitList(id: int): + query = f"SELECT * FROM habit_list WHERE id = {id};" + conn = con3() + cursor = conn.cursor() + cursor.execute(query) + habit_list = cursor.fetchone() + conn.close() + return habit_list + + +def get_habitLists(user_id: int): + query = f"SELECT * FROM habit_list WHERE user_id = {user_id};" + conn = con3() + cursor = conn.cursor() + cursor.execute(query) + habit_lists = cursor.fetchall() + conn.close() + return habit_lists + + +def update_habitList(id: int, name: str, description: str): + now = datetime.now().isoformat() + query = f"UPDATE habit_list SET name = {name}, description = {description}, updated_at = '{now}' WHERE id = {id};" + conn = con3() + cursor = conn.cursor() + cursor.execute(query) + conn.commit() + conn.close() + return cursor.lastrowid + + +def delete_habitList(id: int): + query = f"DELETE FROM habit_list WHERE id = {id};" + conn = con3() + cursor = conn.cursor() + cursor.execute(query) + conn.commit() + conn.close() + + if __name__ == "__main__": habits = get_habits(1) for habit in habits: diff --git a/db/migrations/1705434250_create_habit_lists_table.sql b/db/migrations/1705434250_create_habit_lists_table.sql new file mode 100644 index 0000000..36bd24e --- /dev/null +++ b/db/migrations/1705434250_create_habit_lists_table.sql @@ -0,0 +1,7 @@ +CREATE TABLE IF NOT EXISTS habit_lists ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + name TEXT NOT NULL, + description TEXT, + created_at TEXT NOT NULL, + updated_at TEXT NOT NULL +); \ No newline at end of file diff --git a/db/migrations/1705434250_create_habit_lists_users_relation.sql b/db/migrations/1705434250_create_habit_lists_users_relation.sql new file mode 100644 index 0000000..c201f43 --- /dev/null +++ b/db/migrations/1705434250_create_habit_lists_users_relation.sql @@ -0,0 +1,9 @@ +CREATE TABLE IF NOT EXISTS habit_users ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + user_id INTEGER, + list_id INTEGER, + created_at TEXT NOT NULL, + updated_at TEXT NOT NULL, + FOREIGN KEY (user_id) REFERENCES users(id), + FOREIGN KEY (list_id) REFERENCES habit_lists(id) +); \ No newline at end of file diff --git a/db/migrations/1705434260_create_habits_table.sql b/db/migrations/1705434260_create_habits_table.sql index a38dd47..b02a86a 100644 --- a/db/migrations/1705434260_create_habits_table.sql +++ b/db/migrations/1705434260_create_habits_table.sql @@ -1,7 +1,7 @@ CREATE TABLE IF NOT EXISTS habits ( id INTEGER PRIMARY KEY AUTOINCREMENT, - user_id INTEGER NOT NULL, + list_id INTEGER NOT NULL, name TEXT NOT NULL, note TEXT, times INTEGER NOT NULL, @@ -9,5 +9,5 @@ CREATE TABLE IF NOT EXISTS habits slot INTEGER NOT NULL, created_at TEXT NOT NULL, updated_at TEXT NOT NULL, - FOREIGN KEY (user_id) REFERENCES users(id) + FOREIGN KEY (list_id) REFERENCES habit_lists(id) ); \ No newline at end of file diff --git a/db/migrations/1706001378_create_habit_trackings.sql b/db/migrations/1706001378_create_habit_trackings.sql index 924617a..c3de725 100644 --- a/db/migrations/1706001378_create_habit_trackings.sql +++ b/db/migrations/1706001378_create_habit_trackings.sql @@ -2,7 +2,6 @@ CREATE TABLE IF NOT EXISTS habit_trackings ( id INTEGER PRIMARY KEY AUTOINCREMENT, habit_id INTEGER, - times INTEGER NOT NULL, created_at TEXT NOT NULL, FOREIGN KEY (habit_id) REFERENCES habits(id) ); \ No newline at end of file diff --git a/models/Habit.py b/models/Habit.py index 41a310d..27d4f55 100644 --- a/models/Habit.py +++ b/models/Habit.py @@ -16,7 +16,7 @@ from db.SQLiteClient import update_slot, create_habit, get_habit, delete_habit, @dataclass class Habit: id: int - user_id: int + list_id: int name: str note: str times: int @@ -28,10 +28,10 @@ class Habit: self.fill_statistics() @staticmethod - def create(user_id: int, name: str, times: int, note: str | None = None, unit: int | None = 1): - slot = get_next_slot(user_id) - id = create_habit(user_id, name, times, unit, slot, note) - return Habit(id, user_id, name, note, times, unit, slot) + def create(list_id: int, name: str, times: int, note: str | None = None, unit: int | None = 1): + slot = get_next_slot(list_id) + id = create_habit(list_id, name, times, unit, slot, note) + return Habit(id, list_id, name, note, times, unit, slot) @staticmethod def get(id: int): @@ -54,7 +54,7 @@ class Habit: def update_slot(self, new_slot: int): - slots = get_slots(self.user_id) + slots = get_slots(self.list_id) if new_slot > self.slot: slots = slots[self.slot:new_slot] for slot in slots: @@ -67,7 +67,7 @@ class Habit: def delete(self): - slots = get_slots(self.user_id)[self.slot+1:] + slots = get_slots(self.list_id)[self.slot+1:] print(slots) for slot in slots: update_slot(slot[0], slot[1] - 1) @@ -77,7 +77,7 @@ class Habit: def get_habitTrackings(self) -> list[HabitTrackings]: trackings = [] for rawTracking in get_habitTrackings_by_habit_id(self.id): - trackings.append(HabitTrackings(rawTracking[0], rawTracking[1], rawTracking[2], datetime.strptime(rawTracking[3], "%Y-%m-%dT%H:%M:%S.%f"))) + trackings.append(HabitTrackings(rawTracking[0], rawTracking[1], datetime.strptime(rawTracking[2], "%Y-%m-%dT%H:%M:%S.%f"))) return trackings diff --git a/models/HabitList.py b/models/HabitList.py new file mode 100644 index 0000000..7cecc4b --- /dev/null +++ b/models/HabitList.py @@ -0,0 +1,38 @@ +from dataclasses import dataclass +from datetime import date, datetime + +from db.SQLiteClient import create_habitTrackings, get_habitTrackings, delete_habitTrackings, create_habitList, \ + get_habitList, get_habits +from models.Habit import Habit + + +@dataclass +class HabitList: + id: int + user_id: int + name: str + description: str + created_at: date + updated_at: date + + @staticmethod + def create(user_id: int, name: str, description: str): + id = create_habitList(user_id, name, description) + return HabitList(id, user_id, name, description, datetime.now(), datetime.now()) + + @staticmethod + def get(id: int): + habitList = get_habitList(id) + return HabitList(habitList[0], habitList[1], habitList[2], habitList[3], datetime.strptime(habitList[4], "%Y-%m-%dT%H:%M:%S.%f"), datetime.strptime(habitList[5], "%Y-%m-%dT%H:%M:%S.%f")) if habitList else None + + def delete(self): + delete_habitTrackings(self.id) + + def get_habits(self): + raw_habits = get_habits(self.id) + habits = [] + for habit in raw_habits: + habit = Habit(habit[0], habit[1], habit[2], habit[3], habit[4], habit[5], habit[6]) + habits.append(habit) + + return habits diff --git a/models/HabitTrackings.py b/models/HabitTrackings.py index 33c03b6..9ad30f1 100644 --- a/models/HabitTrackings.py +++ b/models/HabitTrackings.py @@ -8,18 +8,17 @@ from db.SQLiteClient import create_habitTrackings, get_habitTrackings, delete_ha class HabitTrackings: id: int habit_id: int - times: int created_at: date @staticmethod def create(habit_id: int, times: int): - id = create_habitTrackings(habit_id, times) - return HabitTrackings(id, habit_id, times, datetime.now()) + id = create_habitTrackings(habit_id) + return HabitTrackings(id, habit_id, datetime.now()) @staticmethod def get(id: int): habitTrackings = get_habitTrackings(id) - return HabitTrackings(habitTrackings[0], habitTrackings[1], habitTrackings[2], datetime.strptime(habitTrackings[3], "%Y-%m-%dT%H:%M:%S.%f")) if habitTrackings else None + return HabitTrackings(habitTrackings[0], habitTrackings[1], datetime.strptime(habitTrackings[2], "%Y-%m-%dT%H:%M:%S.%f")) if habitTrackings else None def delete(self): delete_habitTrackings(self.id) diff --git a/models/User.py b/models/User.py index b33395c..6d36d6a 100644 --- a/models/User.py +++ b/models/User.py @@ -1,6 +1,10 @@ +from datetime import datetime + from flask_login import UserMixin -from db.SQLiteClient import create_user, get_user, get_user_by_email, get_habits, delete_user, update_user +from db.SQLiteClient import create_user, get_user, get_user_by_email, get_habits, delete_user, update_user, \ + get_habitLists from models.Habit import Habit +from models.HabitList import HabitList class User(UserMixin): @@ -31,10 +35,19 @@ class User(UserMixin): def delete(self): delete_user(self.id) - def get_habits(self): - raw_habits = get_habits(self.id) - habits = [] - for habit in raw_habits: - habit = Habit(habit[0], habit[1], habit[2], habit[3], habit[4], habit[5], habit[6]) - habits.append(habit) - return habits + # def get_habits(self): + # raw_habits = get_habits(self.id) + # habits = [] + # for habit in raw_habits: + # habit = Habit(habit[0], habit[1], habit[2], habit[3], habit[4], habit[5], habit[6]) + # habits.append(habit) + # return habits + + def get_habitLists(self): + raw_habitLists = get_habitLists(self.id) + habitLists = [] + for habitList in raw_habitLists: + habitList = HabitList(habitList[0], habitList[1], habitList[2], habitList[3], datetime.strptime(habitList[4], "%Y-%m-%dT%H:%M:%S.%f"), datetime.strptime(habitList[5], "%Y-%m-%dT%H:%M:%S.%f")) + habitLists.append(habitList) + + return habitLists