Compare commits

...

3 Commits

Author SHA1 Message Date
Verox
05b5869be7 Small update with bug fixes 2024-02-12 22:31:51 +01:00
Verox
4764112296 Finished Multi-Habit-List feature and multiple habits for each habit_list 2024-02-12 22:06:27 +01:00
Verox
4dd997ce13 Added models and relations 2024-02-12 21:07:55 +01:00
28 changed files with 541 additions and 522 deletions

BIN
ER.dia

Binary file not shown.

BIN
UML.dia

Binary file not shown.

79
app.py
View File

@ -5,6 +5,7 @@ from flask import Flask, render_template, redirect, url_for, request
from flask_login import login_required, LoginManager, login_user, logout_user, current_user from flask_login import login_required, LoginManager, login_user, logout_user, current_user
from models.Habit import Habit from models.Habit import Habit
from models.HabitList import HabitList
from models.HabitTrackings import HabitTrackings from models.HabitTrackings import HabitTrackings
from models.User import User from models.User import User
from utils import anonymous_required from utils import anonymous_required
@ -120,20 +121,21 @@ def logout():
@app.route('/') @app.route('/')
def index(): def index():
if current_user.is_authenticated: if current_user.is_authenticated:
habits = current_user.get_habits() habit_lists = current_user.get_habitLists()
name = "Hallo " + current_user.name name = "Hallo " + current_user.name
else: else:
habits = [] habit_lists = []
name = "Bitte melde dich an." name = "Bitte melde dich an."
# Sort habits by whether they have been checked today and then by slot # Sort habits by whether they have been checked today and then by slot
habits.sort(key=lambda habit: (habit.checked, habit.slot)) for habit_list in habit_lists:
habit_list.habits = sorted(habit_list.get_habits(), key=lambda habit: (not habit.checked, habit.slot))
return render_template( return render_template(
'index.html', 'index.html',
title=name, title=name,
utc_dt=datetime.datetime.now().strftime("%d.%m.%Y %H:%M %A"), utc_dt=datetime.datetime.now().strftime("%d.%m.%Y %H:%M %A"),
habits=habits, habit_lists=habit_lists,
errors={}, errors={},
) )
@ -156,6 +158,7 @@ def habit_create():
note = request.form.get('note') note = request.form.get('note')
times = request.form.get('times') times = request.form.get('times')
unit = request.form.get('unit') unit = request.form.get('unit')
list_id = request.form.get('list_query')
# Check for errors # Check for errors
errors = {} errors = {}
@ -167,6 +170,8 @@ def habit_create():
note = '' note = ''
if not unit: if not unit:
errors['unit'] = 'Die Einheit ist erforderlich.' errors['unit'] = 'Die Einheit ist erforderlich.'
if not list_id:
errors['list_query'] = 'Die Habitliste ist erforderlich.'
# Check if times is an integer # Check if times is an integer
try: try:
@ -190,7 +195,8 @@ def habit_create():
note=note, note=note,
times=times, times=times,
unit=unit, unit=unit,
errors=errors errors=errors,
list_id=list_id
) )
# Map unit to integer # Map unit to integer
@ -212,6 +218,45 @@ def habit_create():
return redirect(url_for('index')) return redirect(url_for('index'))
@app.route('/habit-list')
@login_required
def habit_list_creation():
return render_template(
'habit-list.html',
title='Erstelle eine Habitliste',
errors={},
)
@app.route('/habit-list', methods=['POST'])
@login_required
def habit_list_create():
name = request.form.get('name')
description = request.form.get('description')
# Check for errors
errors = {}
if not name:
errors['name'] = 'Der Name ist erforderlich.'
if not description:
note = ''
if errors:
return render_template(
'habit-list.html',
title='Erstelle eine Habitliste',
name=name,
description=description,
errors=errors
)
# Save habit to database
habit = HabitList.create(current_user.id, name, description)
# Back to index
return redirect(url_for('index'))
@app.route('/profile') @app.route('/profile')
@login_required @login_required
def profile(): def profile():
@ -280,7 +325,8 @@ def check_habit():
return {"error": "Habit not found"} return {"error": "Habit not found"}
# Check if habit belongs to user # Check if habit belongs to user
if habit.user_id != current_user.id: users = habit.habit_list().get_users()
if current_user not in users:
return {"error": "Habit does not belong to user"} return {"error": "Habit does not belong to user"}
trackings = habit.get_habitTrackings() trackings = habit.get_habitTrackings()
@ -316,13 +362,32 @@ def delete_habit():
return {"error": "Habit not found"} return {"error": "Habit not found"}
# Check if habit belongs to user # Check if habit belongs to user
if habit.user_id != current_user.id: if current_user not in habit.habit_list().get_users():
return {"error": "Habit does not belong to user"} return {"error": "Habit does not belong to user"}
habit.delete() habit.delete()
return {} 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
users = habit.habit_list().get_users()
if current_user not in users:
return {"error": "Habit does not belong to user"}
habit.update_slot(new_index)
return {}
# Run the application # Run the application
if __name__ == '__main__': if __name__ == '__main__':
app.run(port=5000, debug=True) app.run(port=5000, debug=True)

View File

@ -57,7 +57,7 @@ def update_user(id: int, name: str, email: str, password: str = None):
def delete_user(id: int): 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};" query2 = f"DELETE FROM users WHERE id = {id};"
conn = con3() conn = con3()
cursor = conn.cursor() cursor = conn.cursor()
@ -69,9 +69,9 @@ def delete_user(id: int):
### Habit.py ### ### 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() 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}');") f"'{name}', '{note}', '{times}', '{unit}', '{slot}', '{now}', '{now}');")
conn = con3() conn = con3()
cursor = conn.cursor() cursor = conn.cursor()
@ -91,8 +91,8 @@ def get_habit(id: int):
return habit return habit
def get_habits(user_id: int): def get_habits(list_id: int):
query = f"SELECT * FROM habits WHERE user_id = {user_id};" query = f"SELECT * FROM habits WHERE list_id = {list_id};"
conn = con3() conn = con3()
cursor = conn.cursor() cursor = conn.cursor()
cursor.execute(query) cursor.execute(query)
@ -102,28 +102,50 @@ def get_habits(user_id: int):
def get_heatmap_value(user_id: int, days: int): def get_heatmap_value(user_id: int, days: int):
# Berechnet das Datum, ab dem die Habits gezählt werden sollen
date = (datetime.now() - timedelta(days=days)).date() date = (datetime.now() - timedelta(days=days)).date()
print(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} " # Uses JOINs to get all Habits
f"AND habits.created_at LIKE '{date}%' AND habit_trackings.habit_id = habits.id;") query = (f"SELECT habits.id FROM habits "
print(query2) f"JOIN habit_lists ON habits.list_id = habit_lists.id "
f"JOIN habit_users ON habit_lists.id = habit_users.list_id "
f"WHERE habit_users.user_id = {user_id};")
# Uses JOINs to get all checked Habits on a specific date
query2 = (f"SELECT habits.id FROM habits "
f"JOIN habit_lists ON habits.list_id = habit_lists.id "
f"JOIN habit_users ON habit_lists.id = habit_users.list_id "
f"JOIN habit_trackings ON habits.id = habit_trackings.habit_id "
f"WHERE habit_users.user_id = {user_id} AND DATE(habit_trackings.created_at) = '{date}';")
conn = con3() conn = con3()
cursor = conn.cursor() cursor = conn.cursor()
# Execute the queries
cursor.execute(query) cursor.execute(query)
all_habits = cursor.fetchall() all_habits = cursor.fetchall()
cursor.execute(query2) cursor.execute(query2)
checked_habits = cursor.fetchall() checked_habits = cursor.fetchall()
# Close the database connection
count = len(all_habits) count = len(all_habits)
print(count) print(count)
count2 = len(checked_habits) count2 = len(checked_habits)
print(count2) print(count2)
# Close the database connection
conn.close() conn.close()
# Calculate the percentage of checked Habits
if count > 0:
return int(count2 / count * 100) return int(count2 / count * 100)
else:
return 0
def get_next_slot(user_id: int): def get_next_slot(list_id: int):
query = f"SELECT slot FROM habits WHERE user_id = {user_id} ORDER BY slot DESC LIMIT 1;" query = f"SELECT slot FROM habits WHERE list_id = {list_id} ORDER BY slot DESC LIMIT 1;"
conn = con3() conn = con3()
cursor = conn.cursor() cursor = conn.cursor()
cursor.execute(query) cursor.execute(query)
@ -132,8 +154,8 @@ def get_next_slot(user_id: int):
return slot[0] + 1 if slot else 0 return slot[0] + 1 if slot else 0
def get_slots(user_id: int): def get_slots(list_id: int):
query = f"SELECT id, slot FROM habits WHERE user_id = {user_id} ORDER BY slot;" query = f"SELECT id, slot FROM habits WHERE list_id = {list_id} ORDER BY slot;"
conn = con3() conn = con3()
cursor = conn.cursor() cursor = conn.cursor()
cursor.execute(query) cursor.execute(query)
@ -174,10 +196,10 @@ def delete_habit(id: int):
### HabitTrackings.py ### ### HabitTrackings.py ###
def create_habitTrackings(habit_id: int, times: int): def create_habitTrackings(habit_id: int):
now = datetime.now().isoformat() now = datetime.now().isoformat()
query = ( 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() conn = con3()
cursor = conn.cursor() cursor = conn.cursor()
cursor.execute(query) cursor.execute(query)
@ -215,6 +237,74 @@ def delete_habitTrackings(id: int):
conn.close() conn.close()
### HabitList.py ###
def create_habitList(user_id: int, name: str, description: str):
now = datetime.now().isoformat()
query = (
f"INSERT INTO habit_lists (name, description, created_at, updated_at) VALUES ('{name}', '{description}', '{now}', '{now}');")
conn = con3()
cursor = conn.cursor()
cursor.execute(query)
query1 = f"INSERT INTO habit_users (user_id, list_id, created_at, updated_at) VALUES ('{user_id}', '{cursor.lastrowid}', '{now}', '{now}');"
cursor.execute(query1)
conn.commit()
conn.close()
return cursor.lastrowid
def get_habitList(id: int):
query = f"SELECT * FROM habit_lists 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 habit_lists.* FROM habit_lists JOIN habit_users ON habit_lists.id = habit_users.list_id WHERE habit_users.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_lists 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_lists WHERE id = {id};"
conn = con3()
cursor = conn.cursor()
cursor.execute(query)
conn.commit()
conn.close()
def get_users(list_id: int):
query = f"SELECT users.* FROM users JOIN habit_users ON users.id = habit_users.user_id WHERE habit_users.list_id = {list_id};"
conn = con3()
cursor = conn.cursor()
cursor.execute(query)
users = cursor.fetchall()
conn.close()
return users
if __name__ == "__main__": if __name__ == "__main__":
habits = get_habits(1) habits = get_habits(1)
for habit in habits: for habit in habits:

View File

@ -1,9 +0,0 @@
CREATE TABLE IF NOT EXISTS habits
(
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
note TEXT NULL,
times INTEGER NOT NULL,
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL
);

View File

@ -1 +0,0 @@
DROP TABLE habits;

View File

@ -1,12 +0,0 @@
CREATE TABLE IF NOT EXISTS habits
(
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER,
name TEXT NOT NULL,
note TEXT,
times INTEGER NOT NULL,
unit INTEGER,
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL,
FOREIGN KEY (user_id) REFERENCES users(id)
);

View File

@ -1 +0,0 @@
DROP TABLE habits;

View File

@ -1,13 +0,0 @@
CREATE TABLE IF NOT EXISTS habits
(
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL,
name TEXT NOT NULL,
note TEXT,
times INTEGER NOT NULL,
unit INTEGER,
list_index INTEGER NOT NULL,
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL,
FOREIGN KEY (user_id) REFERENCES users(id)
);

View File

@ -1 +0,0 @@
DROP TABLE habits;

View File

@ -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
);

View File

@ -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)
);

View File

@ -1,7 +1,7 @@
CREATE TABLE IF NOT EXISTS habits CREATE TABLE IF NOT EXISTS habits
( (
id INTEGER PRIMARY KEY AUTOINCREMENT, id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL, list_id INTEGER NOT NULL,
name TEXT NOT NULL, name TEXT NOT NULL,
note TEXT, note TEXT,
times INTEGER NOT NULL, times INTEGER NOT NULL,
@ -9,5 +9,5 @@ CREATE TABLE IF NOT EXISTS habits
slot INTEGER NOT NULL, slot INTEGER NOT NULL,
created_at TEXT NOT NULL, created_at TEXT NOT NULL,
updated_at TEXT NOT NULL, updated_at TEXT NOT NULL,
FOREIGN KEY (user_id) REFERENCES users(id) FOREIGN KEY (list_id) REFERENCES habit_lists(id)
); );

View File

@ -1,2 +0,0 @@
INSERT INTO users (name, email, password, created_at, updated_at)
VALUES ('Nikolaus MikeyMouse', 'Nordpol@icloud.com', 'a36c101570cc4410993de5385ad7034adb2dae6a05139ac7672577803084634d', '23:00', '23:00');

View File

@ -1,2 +0,0 @@
INSERT INTO habits (user_id, name, note, times, unit, slot, created_at, updated_at)
VALUES ('1', 'Sport', '10x Liegestutze', '1', '1', '1', '23:00', '23:00');

View File

@ -1,2 +0,0 @@
INSERT INTO habits (user_id, name, note, times, unit, slot, created_at, updated_at)
VALUES ('1', 'Sport', '10x Klimmzuge', '1', '1', '3', '23:00', '23:00');

View File

@ -1,2 +0,0 @@
INSERT INTO habits (user_id, name, note, times, unit, slot, created_at, updated_at)
VALUES ('1', 'Essen', '1x Gemüse', '1', '2', '2', '23:00', '23:00');

View File

@ -1,2 +0,0 @@
INSERT INTO habits (user_id, name, note, times, unit, slot, created_at, updated_at)
VALUES ('2', 'Sport', '10x Liegestutze', '1', '1', '2', '23:00', '23:00');

View File

@ -2,7 +2,6 @@ CREATE TABLE IF NOT EXISTS habit_trackings
( (
id INTEGER PRIMARY KEY AUTOINCREMENT, id INTEGER PRIMARY KEY AUTOINCREMENT,
habit_id INTEGER, habit_id INTEGER,
times INTEGER NOT NULL,
created_at TEXT NOT NULL, created_at TEXT NOT NULL,
FOREIGN KEY (habit_id) REFERENCES habits(id) FOREIGN KEY (habit_id) REFERENCES habits(id)
); );

View File

@ -4,7 +4,7 @@ from datetime import datetime
from models.HabitTrackings import HabitTrackings from models.HabitTrackings import HabitTrackings
from db.SQLiteClient import update_slot, create_habit, get_habit, delete_habit, get_next_slot, \ from db.SQLiteClient import update_slot, create_habit, get_habit, delete_habit, get_next_slot, \
get_habitTrackings_by_habit_id, get_slots, update_habit get_habitTrackings_by_habit_id, get_slots, update_habit, get_habitList, get_habitLists
# Unit wird als Integers wie folgt gemessen: # Unit wird als Integers wie folgt gemessen:
@ -16,7 +16,7 @@ from db.SQLiteClient import update_slot, create_habit, get_habit, delete_habit,
@dataclass @dataclass
class Habit: class Habit:
id: int id: int
user_id: int list_id: int
name: str name: str
note: str note: str
times: int times: int
@ -28,10 +28,11 @@ class Habit:
self.fill_statistics() self.fill_statistics()
@staticmethod @staticmethod
def create(user_id: int, name: str, times: int, note: str | None = None, unit: int | None = 1): def create(list_id: int, name: str, times: int, note: str | None = None, unit: int | None = 1):
slot = get_next_slot(user_id) slot = get_next_slot(list_id)
id = create_habit(user_id, name, times, unit, slot, note) print(slot)
return Habit(id, user_id, name, note, times, unit, slot) id = create_habit(list_id, name, times, unit, slot, note)
return Habit(id, list_id, name, note, times, unit, slot)
@staticmethod @staticmethod
def get(id: int): def get(id: int):
@ -54,7 +55,7 @@ class Habit:
def update_slot(self, new_slot: int): def update_slot(self, new_slot: int):
slots = get_slots(self.user_id) slots = get_slots(self.list_id)
if new_slot > self.slot: if new_slot > self.slot:
slots = slots[self.slot:new_slot] slots = slots[self.slot:new_slot]
for slot in slots: for slot in slots:
@ -67,7 +68,7 @@ class Habit:
def delete(self): def delete(self):
slots = get_slots(self.user_id)[self.slot+1:] slots = get_slots(self.list_id)[self.slot+1:]
print(slots) print(slots)
for slot in slots: for slot in slots:
update_slot(slot[0], slot[1] - 1) update_slot(slot[0], slot[1] - 1)
@ -77,7 +78,7 @@ class Habit:
def get_habitTrackings(self) -> list[HabitTrackings]: def get_habitTrackings(self) -> list[HabitTrackings]:
trackings = [] trackings = []
for rawTracking in get_habitTrackings_by_habit_id(self.id): 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 return trackings
@ -115,3 +116,9 @@ class Habit:
def to_json(self): def to_json(self):
return json.dumps(self, default=lambda o: o.__dict__, sort_keys=True, indent=4) return json.dumps(self, default=lambda o: o.__dict__, sort_keys=True, indent=4)
def habit_list(self):
from models.HabitList import HabitList
raw_habitLists = get_habitList(self.list_id)
return HabitList(raw_habitLists[0], raw_habitLists[1], raw_habitLists[2], datetime.strptime(raw_habitLists[3], "%Y-%m-%dT%H:%M:%S.%f"), datetime.strptime(raw_habitLists[4], "%Y-%m-%dT%H:%M:%S.%f")) if raw_habitLists else None

48
models/HabitList.py Normal file
View File

@ -0,0 +1,48 @@
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, get_users
from models.Habit import Habit
from models.User import User
@dataclass
class HabitList:
id: int
name: str
description: str
created_at: date
updated_at: date
habits: list = None
@staticmethod
def create(user_id: int, name: str, description: str):
id = create_habitList(user_id, name, description)
return HabitList(id, name, description, datetime.now(), datetime.now())
@staticmethod
def get(id: int):
habitList = get_habitList(id)
return HabitList(habitList[0], habitList[1], habitList[2], datetime.strptime(habitList[3], "%Y-%m-%dT%H:%M:%S.%f"), datetime.strptime(habitList[4], "%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
def get_users(self):
raw_users = get_users(self.id)
users = []
for user in raw_users:
user = User(user[0], user[1], user[2], user[3])
users.append(user)
return users

View File

@ -8,18 +8,17 @@ from db.SQLiteClient import create_habitTrackings, get_habitTrackings, delete_ha
class HabitTrackings: class HabitTrackings:
id: int id: int
habit_id: int habit_id: int
times: int
created_at: date created_at: date
@staticmethod @staticmethod
def create(habit_id: int, times: int): def create(habit_id: int, times: int):
id = create_habitTrackings(habit_id, times) id = create_habitTrackings(habit_id)
return HabitTrackings(id, habit_id, times, datetime.now()) return HabitTrackings(id, habit_id, datetime.now())
@staticmethod @staticmethod
def get(id: int): def get(id: int):
habitTrackings = get_habitTrackings(id) 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): def delete(self):
delete_habitTrackings(self.id) delete_habitTrackings(self.id)

View File

@ -1,6 +1,8 @@
from datetime import datetime
from flask_login import UserMixin 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, \
from models.Habit import Habit get_habitLists
class User(UserMixin): class User(UserMixin):
@ -31,10 +33,21 @@ class User(UserMixin):
def delete(self): def delete(self):
delete_user(self.id) delete_user(self.id)
def get_habits(self): # def get_habits(self):
raw_habits = get_habits(self.id) # raw_habits = get_habits(self.id)
habits = [] # habits = []
for habit in raw_habits: # for habit in raw_habits:
habit = Habit(habit[0], habit[1], habit[2], habit[3], habit[4], habit[5], habit[6]) # habit = Habit(habit[0], habit[1], habit[2], habit[3], habit[4], habit[5], habit[6])
habits.append(habit) # habits.append(habit)
return habits # return habits
def get_habitLists(self):
from models.HabitList import HabitList
raw_habitLists = get_habitLists(self.id)
habitLists = []
for habitList in raw_habitLists:
habitList = HabitList(habitList[0], habitList[1], habitList[2], datetime.strptime(habitList[3], "%Y-%m-%dT%H:%M:%S.%f"), datetime.strptime(habitList[4], "%Y-%m-%dT%H:%M:%S.%f"))
habitLists.append(habitList)
return habitLists

25
templates/habit-list.html Normal file
View File

@ -0,0 +1,25 @@
{% extends 'layouts/main.html' %}
{% block content %}
<h1 class="mt-5">Habitliste erstellen📋</h1>
<form action="/habit-list" method="POST">
<div class="mb-3">
<label for="name" class="form-label">Name der Liste</label>
<input type="text" class="form-control {% if errors.get('name') %} is-invalid {% endif %}" id="name" name="name" value="{{name}}">
<div class="invalid-feedback">
{{ errors.get('name', '') }}
</div>
</div>
<div class="mb-3">
<label for="description" class="form-label">Beschreibung</label>
<input type="text" class="form-control {% if errors.get('description') %} is-invalid {% endif %}" id="description" name="description" value="{{description}}">
<div class="invalid-feedback">
{{ errors.get('description', '') }}
</div>
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
{% endblock %}

View File

@ -54,6 +54,28 @@
</div> </div>
</div> </div>
<input type="hidden" name="list_query" id="list_query" class="{% if errors.get('list_query') %} is-invalid {% endif %}">
<div class="invalid-feedback">
{{ errors.get('list_query', '') }}
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
// Extracting the list-query from the URL
var listQuery = new URLSearchParams(window.location.search).get('list');
if ("{{ list_id }}" != "") {
listQuery = "{{ list_id }}";
// Add the list_id to the URL
var url = new URL(window.location.href);
url.searchParams.set('list', listQuery);
// window.history.pushState({}, '', url);
}
// Setting the list-query as the value of the hidden input field
document.getElementById('list_query').value = listQuery;
});
</script>
<button type="submit" class="btn btn-primary">Submit</button> <button type="submit" class="btn btn-primary">Submit</button>
</form> </form>

View File

@ -82,20 +82,28 @@
</script> </script>
<div class="col-md-7 col-12"> <div class="col-md-7 col-12">
<div class="row mb-3"> <div class="row mb-3">
<h2 class="col-9">Gewohnheiten</h2> <h2 class="col-9">Gewohnheiten</h2>
<a class="col-3 btn btn-primary" role="button" href="/habit">Gewohnheit erstellen</a> <a class="col-3 btn btn-primary" role="button" href="/habit-list">Neue Liste erstellen</a>
</div>
{% for habit_list in habit_lists %}
<div class="row mb-3">
<h2 class="col-9">{{ habit_list.name }}</h2>
<a class="col-3 btn btn-primary" role="button" href="/habit?list={{ habit_list.id }}">Gewohnheit erstellen</a>
</div> </div>
<ul class="task-list row"> <ul class="task-list row">
{% for habit in habits %} {% for habit in habit_list.habits %}
<li class="row d-flex align-items-center mb-2" id="habit-{{ habit.id }}"> <li class="row d-flex align-items-center mb-2" id="habit-{{ habit.id }}">
<div class="col-auto drag-handle" style="cursor: grab;"> <div class="col-auto drag-handle" style="cursor: grab;">
<i class="bi bi-grip-vertical"></i> <i class="bi bi-grip-vertical"></i>
</div> </div>
<div class="col-auto"> <div class="col-auto">
<input {% if habit.checked %} checked {% endif %} type="checkbox" class="task-checkbox" id="{{habit.id}}" onclick="sendPostRequest('{{habit.id}}')"> <input {% if habit.checked %} checked {% endif %} type="checkbox" class="task-checkbox"
id="{{ habit.id }}"
onclick="sendPostRequest('{{ habit.id }}')">
</div> </div>
<div class="col" style="white-space: nowrap; overflow: hidden; text-overflow: ellipsis"> <div class="col" style="white-space: nowrap; overflow: hidden; text-overflow: ellipsis">
@ -113,18 +121,25 @@
</div> </div>
<button type="button" class="btn btn-xs btn-danger rounded-circle" data-bs-toggle="modal" data-bs-target="#exampleModal" style="width: 40px; height: 40px" onclick="setSelectedHabitId({{habit.id}})"> <button type="button" class="btn btn-xs btn-danger rounded-circle" data-bs-toggle="modal"
data-bs-target="#exampleModal" style="width: 40px; height: 40px"
onclick="setSelectedHabitId({{ habit.id }})">
<i class="bi bi-trash3"></i> <i class="bi bi-trash3"></i>
</button> </button>
<div class="col-12"> <div class="col-12">
<div class="progress" style="height: 2px; width: 90%"> <div class="progress" style="height: 2px; width: 90%">
<div class="progress-bar" id="progress-bar-{{habit.id}}" role="progressbar" style="width: {{ habit.percentage }}%; background-color: {% if habit.percentage >= 100 %} green {% else %} primary {% endif %}" aria-valuenow="{{ habit.percentage }}" aria-valuemin="0" aria-valuemax="100"></div> <div class="progress-bar" id="progress-bar-{{ habit.id }}" role="progressbar"
style="width: {{ habit.percentage }}%; background-color: {% if habit.percentage >= 100 %} green {% else %} primary {% endif %}"
aria-valuenow="{{ habit.percentage }}" aria-valuemin="0"
aria-valuemax="100"></div>
</div> </div>
</div> </div>
</li> </li>
{% endfor %} {% endfor %}
</ul> </ul>
{% endfor %}
</div> </div>
<script> <script>
@ -147,7 +162,9 @@
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button> <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary btn-danger" data-bs-dismiss="modal" onclick="deleteHabit(selectedHabitId)">Löschen</button> <button type="button" class="btn btn-primary btn-danger" data-bs-dismiss="modal"
onclick="deleteHabit(selectedHabitId)">Löschen
</button>
</div> </div>
</div> </div>
</div> </div>
@ -228,8 +245,6 @@
handle: '.drag-handle', handle: '.drag-handle',
animation: 150, animation: 150,
onEnd: function (evt) { onEnd: function (evt) {
console.log(evt.oldIndex, evt.newIndex);
var habitId = el.children[evt.newIndex].id.split('-')[1]; var habitId = el.children[evt.newIndex].id.split('-')[1];
var oldIndex = evt.oldIndex; var oldIndex = evt.oldIndex;
var newIndex = evt.newIndex; var newIndex = evt.newIndex;
@ -240,7 +255,6 @@
} }
}).then(function (response) { }).then(function (response) {
// Handle the success response if needed // Handle the success response if needed
console.log(response.data);
}).catch(function (error) { }).catch(function (error) {
// Handle the error if needed // Handle the error if needed
console.error('Error:', error); console.error('Error:', error);

View File

@ -1,167 +0,0 @@
{% extends 'layouts/main.html' %}
{% block content %}
<h1>{{ title }}</h1>
<h3>{{ utc_dt }}</h3>
<style>
table {
border-collapse: collapse;
width: 100%;
}
th, td {
border: 1px solid #dddddd;
text-align: center;
padding: 8px;
}
th {
background-color: #f2f2f2;
}
.current-week {
/* Change the color for the current week */
background-color: rgba(255, 204, 0, 1); /* Full opacity */
}
.past-week {
/* Change the color for past weeks */
background-color: rgba(224, 224, 224, 1); /* Full opacity */
}
.future-week {
/* Change the color for future weeks */
background-color: rgba(192, 224, 192, 1); /* Full opacity */
}
.current-day {
/* Highlight the current day */
border: 2px solid #ff0000;
border-radius: 5px;
}
</style>
<table id="heatmap">
<thead>
<tr>
<th></th> <!-- Empty cell for spacing -->
<th class="past-week">-2</th>
<th class="past-week">-1</th>
<th class="current-week">0</th>
<th class="future-week">+1</th>
<th class="future-week">+2</th>
</tr>
</thead>
<tbody>
<tr>
<td >Montag</td>
<td class="past-week" data-tasks="5">15</td>
<td class="past-week" data-tasks="8">20</td>
<td class="current-week" data-tasks="12">25</td>
<td class="future-week" data-tasks="7">30</td>
<td class="future-week" data-tasks="10">35</td>
</tr>
<tr>
<td class="current-day">Dienstag</td>
<td class="past-week" data-tasks="5">15</td>
<td class="past-week" data-tasks="8">20</td>
<td class="current-week" data-tasks="12">25</td>
<td class="future-week" data-tasks="7">30</td>
<td class="future-week" data-tasks="10">35</td>
</tr>
<tr>
<td >Mittwoch</td>
<td class="past-week" data-tasks="5">15</td>
<td class="past-week" data-tasks="8">20</td>
<td class="current-week" data-tasks="12">25</td>
<td class="future-week" data-tasks="7">30</td>
<td class="future-week" data-tasks="10">35</td>
</tr>
<tr>
<td >Donnerstag</td>
<td class="past-week" data-tasks="5">15</td>
<td class="past-week" data-tasks="8">20</td>
<td class="current-week" data-tasks="12">25</td>
<td class="future-week" data-tasks="7">30</td>
<td class="future-week" data-tasks="10">35</td>
</tr>
<tr>
<td >Freitag</td>
<td class="past-week" data-tasks="5">15</td>
<td class="past-week" data-tasks="8">20</td>
<td class="current-week" data-tasks="12">25</td>
<td class="future-week" data-tasks="7">30</td>
<td class="future-week" data-tasks="10">35</td>
</tr>
<tr>
<td >Samstag</td>
<td class="past-week" data-tasks="5">15</td>
<td class="past-week" data-tasks="8">20</td>
<td class="current-week" data-tasks="12">25</td>
<td class="future-week" data-tasks="7">30</td>
<td class="future-week" data-tasks="10">35</td>
</tr> <tr>
<td >Sonntag</td>
<td class="past-week" data-tasks="5">15</td>
<td class="past-week" data-tasks="8">20</td>
<td class="current-week" data-tasks="12">25</td>
<td class="future-week" data-tasks="7">30</td>
<td class="future-week" data-tasks="10">35</td>
</tr>
</tbody>
</table>
<script>
// Adjust background color based on the number of tasks
document.addEventListener('DOMContentLoaded', function () {
var cells = document.querySelectorAll('#heatmap tbody td');
cells.forEach(function (cell) {
var tasks = parseInt(cell.getAttribute('data-tasks')) || 0;
var opacity = tasks / 20; // Adjust the denominator based on your preference
// Get the RGB values from the background color
var rgb = cell.style.backgroundColor.match(/\d+/g);
// Calculate the green value based on the number of tasks
var greenValue = Math.round(opacity * 255);
// Set the new background color with adjusted green value
cell.style.backgroundColor = 'rgba(0,' + greenValue + ',0,' + opacity + ')';
});
});
</script>
<div class="row">
<h2 class="col-10">Task List</h2>
<a class="col-2 btn btn-primary" role="button" href="/habit">
Task erstellen
</a>
</div>
<ul class="task-list row">
{% for habit in habits %}
<li class="row col-md-4">
<div class="col-auto">
<input type="checkbox" class="task-checkbox">
</div>
<div class="col" style="white-space: nowrap; overflow: hidden; text-overflow: ellipsis">
{{ habit.name }} hhhbhghbhjndjksbeujsdkfheuwaihgkjfgfjnsidkgjnkdghujds
</div>
</li>
<div class="col-md-8" style="white-space: nowrap; overflow: hidden; text-overflow: ellipsis">
{{ habit.note }}
</div>
{% endfor %}
</ul>
{% endblock %}

View File

@ -1,65 +0,0 @@
{% extends 'layouts/main.html' %}
{% block content %}
<h1>{{ title }}</h1>
<h3>{{ utc_dt }}</h3>
<div class="heatmap" id="heatmap"></div>
<script>
// Simulierte Aktivitätsdaten (ersetze dies durch deine echten Daten)
const activityData = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 5, 4, 3, 2, 1, 9, 5, 36, 75, 8, 9, 1, 0, 23, 0, 0, 0, 64, 0, 0, 64, 0, 0, 19, 84];
// Funktion zum Erstellen der Heatmap
function createHeatmap(data) {
const heatmapContainer = document.getElementById('heatmap');
for (let i = 0; i < data.length; i++) {
const opacity = data[i] / Math.max(...data); // Berechne die Opazität basierend auf Aktivitätsanzahl
const dayElement = document.createElement('div');
dayElement.classList.add('day');
dayElement.style.backgroundColor = `rgba(0, 255, 0, ${opacity})`;
heatmapContainer.appendChild(dayElement);
}
}
// Erstelle die Heatmap mit den simulierten Daten
createHeatmap(activityData);
</script>
<div class="row">
<h2 class="col-10">Task List</h2>
<a class="col-2 btn btn-primary" role="button" href="/habit">
Task erstellen
</a>
</div>
<ul class="task-list row">
{% for habit in habits %}
<li class="row col-md-4">
<div class="col-auto">
<input type="checkbox" class="task-checkbox">
</div>
<div class="col" style="white-space: nowrap; overflow: hidden; text-overflow: ellipsis">
{{ habit.name }} hhhbhghbhjndjksbeujsdkfheuwaihgkjfgfjnsidkgjnkdghujds
</div>
</li>
<div class="col-md-8" style="white-space: nowrap; overflow: hidden; text-overflow: ellipsis">
{{ habit.note }}
</div>
{% endfor %}
</ul>
{% endblock %}