Merge remote-tracking branch 'origin/master'

This commit is contained in:
nikolaswollenberg 2024-03-05 09:44:12 +01:00
commit 3427e8f271
10 changed files with 244 additions and 127 deletions

88
app.py
View File

@ -93,6 +93,10 @@ def signup_post():
if not password: if not password:
errors['password'] = 'Das Passwort ist erforderlich.' errors['password'] = 'Das Passwort ist erforderlich.'
# Check if email is already in use
if User.get_by_email(email):
errors['email'] = 'E-Mail Adresse bereits in Benutzung.'
if errors: if errors:
return render_template( return render_template(
'auth/signup.html', 'auth/signup.html',
@ -135,10 +139,15 @@ def index():
for habit_list in habit_lists: for habit_list in habit_lists:
habit_list.habits = sorted(habit_list.get_habits(), key=lambda habit: (not habit.checked, habit.slot)) habit_list.habits = sorted(habit_list.get_habits(), key=lambda habit: (not habit.checked, habit.slot))
days = {"Monday": "Montag", "Tuesday": "Dienstag", "Wednesday": "Mittwoch", "Thursday": "Donnerstag",
"Friday": "Freitag", "Saturday": "Samstag", "Sunday": "Sonntag"}
date = datetime.datetime.now().strftime("%d.%m.%Y %H:%M ") + days[datetime.datetime.now().strftime("%A")]
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=date,
habit_lists=habit_lists, habit_lists=habit_lists,
heatmap_values=heatmap_values, heatmap_values=heatmap_values,
errors={}, errors={},
@ -571,6 +580,83 @@ def reorder_habits():
return {} return {}
@app.route('/users')
@login_required
def users():
habit_list_id = request.args.get('habit_list', current_user.get_habitLists()[0].id)
habit_list = HabitList.get(int(habit_list_id))
users = habit_list.get_users()
# Remove the current user from the list
users = [user for user in users if user.id != current_user.id]
return render_template(
'users.html',
title='Teilnehmer',
habit_list=habit_list,
users=users,
errors={},
)
@app.route('/users', methods=['POST'])
@login_required
def add_user():
email = request.form.get('email')
habit_list_id = request.form.get('habit_list_id')
habit_list = HabitList.get(int(habit_list_id))
# Check for errors
errors = {}
if not email:
errors['email'] = 'Die E-Mail Adresse ist erforderlich.'
if not habit_list_id:
errors['habit_list'] = 'Die Habitliste ist erforderlich.'
if errors:
return render_template(
'users.html',
title='Teilnehmer',
email=email,
habit_list=habit_list,
errors=errors,
users=habit_list.get_users(),
)
# Check if user exists
user = User.get_by_email(email)
if not user:
errors['email'] = 'E-Mail Adresse nicht gefunden.'
if user.id == current_user.id:
errors['email'] = 'Du kannst dich nicht selbst hinzufügen.'
# Check if user is already in the habit list
already = False
for u in habit_list.get_users():
if u.id == user.id:
already = True
break
if already:
errors['email'] = 'Teilnehmer ist bereits in der Liste.'
if errors:
return render_template(
'users.html',
title='Teilnehmer',
email=email,
habit_list=habit_list,
errors=errors,
users=habit_list.get_users(),
)
# Add user to habit list
habit_list = HabitList.get(int(habit_list_id))
habit_list.add_user(user)
return redirect(url_for('index', habit_list=habit_list.id))
# 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

@ -53,15 +53,14 @@ class HabitList:
raw_users = get_users(self.id) raw_users = get_users(self.id)
users = [] users = []
for user in raw_users: for user in raw_users:
user = User(user[0], user[1], user[2], user[3]) user = User(user[0], user[1], user[2], user[3], user[4])
users.append(user) users.append(user)
return users return users
# Adds a User by email to the HabitList # Adds a User by email to the HabitList
def add_user(self, email: str): def add_user(self, user: User):
user = User.get_by_email(email)
if user: if user:
add_user(self.id, user.id) add_user(self.id, user.id)
else: else:

View File

@ -1,8 +1,8 @@
{% extends 'layouts/main.html' %} {% extends 'layouts/main.html' %}
{% block content %} {% block content %}
<div class="card"> <div class="card bg-light mt-4">
<h5 class="card-header">Login</h5> <h1 class="card-header">Login</h1>
<div class="card-body column"> <div class="card-body column">
<form method="POST" action="/login"> <form method="POST" action="/login">
<div class="mb-3 row"> <div class="mb-3 row">

View File

@ -1,33 +1,38 @@
{% extends 'layouts/main.html' %} {% extends 'layouts/main.html' %}
{% block content %} {% block content %}
<div class="column"> <div class="card bg-light mt-4 p-5">
<h3>Registrieren</h3> <div class="column">
<form method="POST" action="/signup"> <h1>Registrieren</h1>
<div class="mb-3"> <form method="POST" action="/signup">
<label for="email" class="form-label">Email-Adresse</label> <div class="mb-3">
<input type="email" class="form-control {% if errors.get('email') %} is-invalid {% endif %}" id="email" name="email" placeholder="name@example.com" value="{{ email }}"> <label for="email" class="form-label">Email-Adresse</label>
<div class="invalid-feedback"> <input type="email" class="form-control {% if errors.get('email') %} is-invalid {% endif %}" id="email"
{{ errors.get('email', '') }} name="email" placeholder="name@example.com" value="{{ email }}">
<div class="invalid-feedback">
{{ errors.get('email', '') }}
</div>
</div> </div>
</div> <div class="mb-3">
<div class="mb-3"> <label for="name" class="form-label">Name</label>
<label for="name" class="form-label">Name</label> <input type="text" class="form-control {% if errors.get('name') %} is-invalid {% endif %}" id="name"
<input type="text" class="form-control {% if errors.get('name') %} is-invalid {% endif %}" id="name" name="name" placeholder="Max" value="{{ name }}"> name="name" placeholder="Max" value="{{ name }}">
<div class="invalid-feedback"> <div class="invalid-feedback">
{{ errors.get('name', '') }} {{ errors.get('name', '') }}
</div>
</div> </div>
</div> <div class="mb-3">
<div class="mb-3"> <label for="password" class="form-label">Passwort</label>
<label for="password" class="form-label">Passwort</label> <input type="password" class="form-control {% if errors.get('password') %} is-invalid {% endif %}"
<input type="password" class="form-control {% if errors.get('password') %} is-invalid {% endif %}" id="password" name="password" value="{{ password }}"> id="password" name="password" value="{{ password }}">
<div class="invalid-feedback"> <div class="invalid-feedback">
{{ errors.get('password', '') }} {{ errors.get('password', '') }}
</div>
</div> </div>
</div> <div class="col-auto">
<div class="col-auto"> <button type="submit" class="btn btn-primary mb-3">Registrieren</button>
<button type="submit" class="btn btn-primary mb-3">Registrieren</button> </div>
</div> </form>
</form> </div>
</div> </div>
{% endblock %} {% endblock %}

View File

@ -66,24 +66,30 @@
<div class="row mb-3 align-items-center"> <div class="row mb-3 align-items-center">
<!-- Personen die zur Liste gehören --> <!-- Personen die zur Liste gehören -->
<div class="col-2"> {% if habit_list.get_users()[0].id == current_user.id %}
{% if habit_list.get_users()|length > 1 %}
<div class="col">
<div class="avatar-stack"> <div class="avatar-stack">
<img class="avatar" src="/images/avatar/1.jpg"/> {% for user in habit_list.get_users() %}
<img class="avatar" src="/images/avatar/2.jpg"/> {% if current_user.id != user.id %}
<img class="avatar" src="/images/avatar/4.jpg"/> <img class="avatar" src="/{{user.profile_image}}" data-toggle="tooltip" data-placement="top" title="{{user.name}}"/>
<img class="avatar" src="/images/avatar/5.jpg"/> {% endif %}
{% endfor %}
</div> </div>
</div> </div>
{% endif %}
<!-- Knopf für das Hinzufügen einer Person zur gemeinsamen Liste --> <!-- Knopf für das Hinzufügen einer Person zur gemeinsamen Liste -->
<div class="col-1"> <div class="col">
<button type="button" class="btn" <a href="/users?habit_list={{habit_list.id}}" style="width: 40px; height: 40px; min-height: 3em;" data-toggle="tooltip" data-placement="top" title="Benutzer einladen">
style="width: 40px; height: 40px; min-height: 3em;">
<i class="bi bi-plus"></i> <i class="bi bi-plus-circle"></i>
</button> </a>
</div> </div>
{% else %}
<div class="col"></div>
{% endif %}
<div class="col-6"></div> <div class="col-6"></div>
@ -115,7 +121,7 @@
</div> </div>
<!-- Beschreibung --> <!-- Beschreibung -->
<div class="col-md-3 d-none d-md-block text-black text-opacity-50" <div class="col-md-4 d-none d-md-block text-black text-opacity-50"
style="white-space: nowrap; overflow: hidden; text-overflow: ellipsis"> style="white-space: nowrap; overflow: hidden; text-overflow: ellipsis">
{{ habit.note }} {{ habit.note }}
</div> </div>
@ -123,7 +129,7 @@
<!-- Streak --> <!-- Streak -->
<div class="col-2" id="streak-{{ habit.id }}" style="white-space: nowrap; overflow: hidden; text-overflow: ellipsis"> <div class="col-2" id="streak-{{ habit.id }}" style="white-space: nowrap; overflow: hidden; text-overflow: ellipsis">
{% if not habit.streak == 0 %} {% if not habit.streak == 0 %}
{{ habit.streak }} 🔥 {{ habit.streak }}20 🔥
{% endif %} {% endif %}
</div> </div>
@ -134,7 +140,7 @@
<i class="bi bi-trash3"></i> <i class="bi bi-trash3"></i>
</button> </button>
<!-- --> <!-- Knopf für das Bearbeiten der Gewohnheit -->
<a type="button" class="btn" href="{{ url_for('edit_habit') }}?habit={{ habit.id }}" aria-current="page" <a type="button" class="btn" href="{{ url_for('edit_habit') }}?habit={{ habit.id }}" aria-current="page"
style="width: 40px; height: 40px; min-height: 3em;"> style="width: 40px; height: 40px; min-height: 3em;">

View File

@ -1,81 +1,80 @@
<script> <script>
function checkCompletionAndAnimate(habitId, percentage) { function checkCompletionAndAnimate(habitId, percentage) {
var progressBar = document.getElementById("progress-bar-" + habitId); var progressBar = document.getElementById("progress-bar-" + habitId);
var habitBlock = document.getElementById("habit-" + habitId); var habitBlock = document.getElementById("habit-" + habitId);
if (percentage === 100) { if (percentage === 100) {
progressBar.style.backgroundColor = "green"; progressBar.style.backgroundColor = "green";
habitBlock.classList.add("animate-bounce"); habitBlock.classList.add("animate-bounce");
setTimeout(function () { setTimeout(function () {
habitBlock.classList.remove("animate-bounce"); habitBlock.classList.remove("animate-bounce");
}, 2000); }, 2000);
} else { } else {
progressBar.style.backgroundColor = ""; progressBar.style.backgroundColor = "";
habitBlock.classList.remove("animate-bounce"); habitBlock.classList.remove("animate-bounce");
} }
}
function sendPostRequest(checkboxId) {
// Get the checkbox element using the provided ID
var checkbox = document.getElementById(checkboxId);
// console.log(checkbox);
// Get the habit id from the checkbox id attribute
var habitId = checkboxId;
// Make a POST request to /check with the habit id
axios.post('/check', {habitId: habitId}, {
headers: {
'Content-Type': 'application/json'
} }
}).then(function (response) {
function sendPostRequest(checkboxId) { // Handle the success response if needed
// Get the checkbox element using the provided ID console.log(response.data);
var checkbox = document.getElementById(checkboxId);
// console.log(checkbox);
// Get the habit id from the checkbox id attribute
var habitId = checkboxId;
// Make a POST request to /check with the habit id
axios.post('/check', {habitId: habitId}, {
headers: {
'Content-Type': 'application/json'
}
}).then(function (response) {
// Handle the success response if needed
console.log(response.data);
// Set the percentage of the habit. percentage received as integer // Set the percentage of the habit. percentage received as integer
const percentage = response.data.percentage; const percentage = response.data.percentage;
const progressBar = document.getElementById("progress-bar-" + habitId); const progressBar = document.getElementById("progress-bar-" + habitId);
progressBar.style.width = percentage + "%"; progressBar.style.width = percentage + "%";
checkCompletionAndAnimate(habitId, percentage); checkCompletionAndAnimate(habitId, percentage);
const streak = response.data.streak; const streak = response.data.streak;
const streakSymbol = document.getElementById("streak-" + habitId); const streakSymbol = document.getElementById("streak-" + habitId);
streakSymbol.innerText = streak > 0 ? streak.toString() + " 🔥" : ""; streakSymbol.innerText = streak > 0 ? streak.toString() + " 🔥" : "";
}).catch(function (error) { }).catch(function (error) {
// Handle the error if needed // Handle the error if needed
console.error('Error:', error); console.error('Error:', error);
}); });
}
function sendHabitId(Id) {
var habitId = document.getElementById(Id);
// Make a POST request to /check with the habit id
// axios.post('/edit-habit', {editHabitId: habitId})
}
function deleteHabit(habitId) {
// Make a POST request to /delete with the habit id
axios.post('/delete', {habitId: habitId}, {
headers: {
'Content-Type': 'application/json'
} }
}).then(function (response) {
// Handle the success response if needed
console.log(response.data);
function sendHabitId(Id) { // Remove the habit from the DOM
var habitElement = document.getElementById("habit-" + habitId);
var habitId = document.getElementById(Id); habitElement.remove();
}).catch(function (error) {
// Make a POST request to /check with the habit id // Handle the error if needed
// axios.post('/edit-habit', {editHabitId: habitId}) console.error('Error:', error);
} });
}
function deleteHabit(habitId) {
// Make a POST request to /delete with the habit id
axios.post('/delete', {habitId: habitId}, {
headers: {
'Content-Type': 'application/json'
}
}).then(function (response) {
// Handle the success response if needed
console.log(response.data);
// Remove the habit from the DOM
var habitElement = document.getElementById("habit-" + habitId);
habitElement.remove();
}).catch(function (error) {
// Handle the error if needed
console.error('Error:', error);
});
}
document.addEventListener('DOMContentLoaded', (event) => { document.addEventListener('DOMContentLoaded', (event) => {
@ -106,6 +105,7 @@
} }
}); });
$(function () {
$('[data-toggle="tooltip"]').tooltip()
})
</script> </script>

View File

@ -1,8 +1,8 @@
{% extends 'layouts/main.html' %} {% extends 'layouts/main.html' %}
{% block content %} {% block content %}
<div class="card bg-light p-5 mt-5">
<h1 class="mt-5">Habitliste erstellen📋</h1> <h1>Gewohnheitsliste erstellen📋</h1>
<form action="/habit-list" method="POST"> <form action="/habit-list" method="POST">
<div class="mb-3"> <div class="mb-3">
@ -21,5 +21,5 @@
</div> </div>
<button type="submit" class="btn btn-primary">Submit</button> <button type="submit" class="btn btn-primary">Submit</button>
</form> </form>
</div>
{% endblock %} {% endblock %}

View File

@ -1,8 +1,8 @@
{% extends 'layouts/main.html' %} {% extends 'layouts/main.html' %}
{% block content %} {% block content %}
<div class="card bg-light p-5 mt-5">
<h1 class="mt-5">Habit erstellen📋</h1> <h1>Gewohnheit erstellen📋</h1>
<form action="/habit" method="POST"> <form action="/habit" method="POST">
<div class="mb-3"> <div class="mb-3">
@ -78,5 +78,5 @@
</script> </script>
<button type="submit" class="btn btn-primary">Submit</button> <button type="submit" class="btn btn-primary">Submit</button>
</form> </form>
</div>
{% endblock %} {% endblock %}

View File

@ -34,11 +34,7 @@
<span class="navbar-toggler-icon"></span> <span class="navbar-toggler-icon"></span>
</button> </button>
<div class="collapse navbar-collapse" id="navbarSupportedContent"> <div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav me-auto mb-2 mb-lg-0"> <ul class="me-auto"></ul>
<li class="nav-item">
<a class="nav-link text-white {% if title == 'Home' %} active {% endif %}" aria-current="page" href="{{ url_for('index') }}">Home</a>
</li>
</ul>
<ul class="navbar-nav mb-2 mb-lg-0"> <ul class="navbar-nav mb-2 mb-lg-0">
{% if not current_user.is_authenticated %} {% if not current_user.is_authenticated %}
<li class="nav-item me-2"> <li class="nav-item me-2">

25
templates/users.html Normal file
View File

@ -0,0 +1,25 @@
{% extends 'layouts/main.html' %}
{% block content %}
<div class="card bg-light mt-4 p-5">
<h1>{{ habit_list.name }}: {{ title }}</h1>
<p>Lade Nutzer per ihrer E-Mail-Adresse ein</p>
<form action="/users" method="POST">
<div class="mb-3">
<label for="email" class="form-label">E-Mail</label>
<input type="text" placeholder="beispiel@cimeyclust.com"
class="form-control {% if errors.get('email') %} is-invalid {% endif %}" id="email" name="email"
value="{{email}}">
<div class="invalid-feedback">
{{ errors.get('email', '') }}
</div>
</div>
<input hidden="hidden" name="habit_list_id" value="{{ habit_list.id }}">
<!-- submit button -->
<button type="submit" class="btn btn-primary">Einladen</button>
</form>
</div>
{% endblock %}