diff --git a/app.py b/app.py index 5f52993..2eed89e 100644 --- a/app.py +++ b/app.py @@ -32,6 +32,7 @@ def load_user(user_id): def inject_user(): return dict(user=current_user) + @app.context_processor def inject_notifications(): if current_user.is_authenticated: @@ -173,6 +174,7 @@ def index(): ) +########################## Habit ########################## @app.route('/habit') @login_required def habit_creation(): @@ -183,7 +185,6 @@ def habit_creation(): errors={}, ) - @app.route('/habit', methods=['POST']) @login_required def habit_create(): @@ -266,80 +267,6 @@ def habit_create(): # Back to 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: - description = '' - - if errors: - return render_template( - 'habit-list.html', - title='Erstelle eine Habitliste', - name=name, - description=description, - errors=errors - ) - - # Save habit to database - HabitList.create(current_user.id, name, description) - - # Back to index - return redirect(url_for('index')) - - -@app.route('/profile') -@login_required -def profile(): - return render_template( - "profile.html", - name=current_user.name, - email=current_user.email, - profile_image_url=current_user.profile_image, - color = current_user.heatmap_color, - title="Profil", - ) - - -@app.route('/profile', methods=['POST']) -@login_required -def profile_change(): - newName = request.form.get('newName') - newEmail = request.form.get('newEmail') - - # Update user - current_user.name = newName - current_user.email = newEmail - current_user.update() - - # Back to profile - return render_template( - "profile.html", - name=current_user.name, - email=current_user.email, - profile_image_url=current_user.profile_image, - color=current_user.heatmap_color, - ) - - @app.route('/edit-habit') @login_required def edit_habit(): @@ -360,7 +287,6 @@ def edit_habit(): errors={} ) - @app.route('/edit-habit', methods=['POST']) @login_required def edit_habit_change(): @@ -451,122 +377,6 @@ def edit_habit_change(): # Back to index return redirect(url_for('index')) - -@app.route('/check_password', methods=['POST']) -@login_required -def check_password(): - # Get the password sent from the client - password = request.json.get('password') - - if hashlib.sha256(password.encode()).hexdigest() == current_user.password: - return jsonify({"valid": True}) - else: - return jsonify({"valid": False}) - - -@app.route('/password', methods=['POST']) -@login_required -def password_change(): - newPassword = request.form.get('newPassword') - - # Update user - if newPassword: - current_user.password = hashlib.sha256(newPassword.encode()).hexdigest() - current_user.update() - - # Back to profile - return render_template( - "profile.html", - name=current_user.name, - email=current_user.email, - profile_image_url=current_user.profile_image, - color=current_user.heatmap_color, - ) - - -def save_profile_image(image_file): - filename = image_file.filename - if '.' not in filename: - # Ensure the filename has an extension - raise ValueError("Invalid filename") - - # Check if the file extension is allowed - allowed_extensions = {'jpg', 'jpeg', 'png', 'gif'} - file_extension = filename.rsplit('.', 1)[1].lower() - if file_extension not in allowed_extensions: - raise ValueError("Invalid file extension") - - # Get the filename from the image path saved in the user - filename = os.path.basename(current_user.profile_image) - image_path = os.path.join(app.config['UPLOAD_FOLDER'], filename) - os.remove(image_path) - - # Check if the image is an animated gif - if file_extension == 'gif': - gif_path = os.path.join(app.config['UPLOAD_FOLDER'], filename.replace(".jpg", ".gif")) - image_file.save(gif_path) - - current_user.profile_image = gif_path - current_user.update() - return - - # Open the uploaded image - image = Image.open(image_file) - - # Convert the image to RGB mode (required for JPEG) - image = image.convert('RGB') - - # Determine the size of the square image - min_dimension = min(image.size) - square_size = (min_dimension, min_dimension) - - # Calculate the coordinates for cropping - left = (image.width - min_dimension) / 2 - top = (image.height - min_dimension) / 2 - right = (image.width + min_dimension) / 2 - bottom = (image.height + min_dimension) / 2 - - # Crop the image to a square and resize it - image = image.crop((left, top, right, bottom)) - image.thumbnail(square_size) - image = image.resize((256, 256)) - - # Save the processed image - image_path = os.path.join(app.config['UPLOAD_FOLDER'], filename.replace(".gif", ".jpg")) - image.save(image_path, 'JPEG', quality=100) - current_user.profile_image = image_path - current_user.update() - - -@app.route('/upload', methods=['POST']) -def upload_profile_image(): - if 'file' not in request.files: - return 'No file part' - - file = request.files['file'] - save_profile_image(file) - - # Back to profile - return redirect(url_for('profile')) - - -@app.route('/save_color', methods=['POST']) -def save_heatmap_color(): - # Get the color value from the form - new_color = request.form['color'] - current_user.heatmap_color = new_color - current_user.update() - - # Back to profile - return render_template( - "profile.html", - name=current_user.name, - email=current_user.email, - profile_image_url=current_user.profile_image, - color=current_user.heatmap_color, - ) - - @app.route('/check', methods=['POST']) @login_required def check_habit(): @@ -608,7 +418,6 @@ def check_habit(): "day": day, } - @app.route('/delete', methods=['POST']) @login_required def delete_habit(): @@ -626,25 +435,6 @@ def delete_habit(): habit.delete() return {} - -@app.route('/delete-list', methods=['POST']) -@login_required -def delete_list(): - list_id = request.get_json()["listId"] - - habit_list = HabitList.get(list_id) - - if habit_list is None: - return {"error": "List not found"} - - # Check if habit belongs to user - if current_user not in habit_list.get_users(): - return {"error": "List does not belong to user"} - - habit_list.delete(current_user.id) - return {} - - @app.route('/reorder', methods=['POST']) @login_required def reorder_habits(): @@ -662,8 +452,65 @@ def reorder_habits(): habit.update_slot(new_index) return {} +########################################################### + +######################## HabitList ######################## +@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: + description = '' + + if errors: + return render_template( + 'habit-list.html', + title='Erstelle eine Habitliste', + name=name, + description=description, + errors=errors + ) + + # Save habit to database + HabitList.create(current_user.id, name, description) + + # Back to index + return redirect(url_for('index')) + +@app.route('/delete-list', methods=['POST']) +@login_required +def delete_list(): + list_id = request.get_json()["listId"] + + habit_list = HabitList.get(list_id) + + if habit_list is None: + return {"error": "List not found"} + + # Check if habit belongs to user + if current_user not in habit_list.get_users(): + return {"error": "List does not belong to user"} + + habit_list.delete(current_user.id) + return {} + @app.route('/users') @login_required def users(): @@ -682,67 +529,6 @@ def users(): errors={}, ) - -@app.route('/users-edit') -@login_required -def edit_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-edit.html', - title='Teilnehmer bearbeiten', - habit_list=habit_list, - users=users, - errors={}, - ) - - -@app.route('/user-delete', methods=['POST']) -@login_required -def delete_user_from_list(): - habit_list_id = request.form.get('habit_list_id') - habit_list = HabitList.get(int(habit_list_id)) - - habit_user_id = request.form.get('habit_user_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] - - # Check for errors - errors = {} - if not habit_list_id: - errors['habit_list'] = 'Die Habitliste ist erforderlich.' - if not habit_list_id: - errors['habit_user'] = 'Ein User ist erforderlich.' - - if errors: - return render_template( - 'users-edit.html', - title='Teilnehmer bearbeiten', - habit_list=habit_list, - users=users, - errors={}, - ) - - # delete user from habit list - id = int(habit_user_id) - habit_list.delete(id) - - return render_template( - 'users-edit.html', - title='Teilnehmer bearbeiten', - habit_list=habit_list, - users=users, - errors={}, - ) - - @app.route('/users', methods=['POST']) @login_required def add_user(): @@ -802,6 +588,63 @@ def add_user(): return redirect(url_for('index', habit_list=habit_list.id)) +@app.route('/users-edit') +@login_required +def edit_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-edit.html', + title='Teilnehmer bearbeiten', + habit_list=habit_list, + users=users, + errors={}, + ) + +@app.route('/user-delete', methods=['POST']) +@login_required +def delete_user_from_list(): + habit_list_id = request.form.get('habit_list_id') + habit_list = HabitList.get(int(habit_list_id)) + + habit_user_id = request.form.get('habit_user_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] + + # Check for errors + errors = {} + if not habit_list_id: + errors['habit_list'] = 'Die Habitliste ist erforderlich.' + if not habit_list_id: + errors['habit_user'] = 'Ein User ist erforderlich.' + + if errors: + return render_template( + 'users-edit.html', + title='Teilnehmer bearbeiten', + habit_list=habit_list, + users=users, + errors={}, + ) + + # delete user from habit list + id = int(habit_user_id) + habit_list.delete(id) + + return render_template( + 'users-edit.html', + title='Teilnehmer bearbeiten', + habit_list=habit_list, + users=users, + errors={}, + ) @app.route('/users-leave') @login_required @@ -820,7 +663,6 @@ def user_leave(): habit_list.remove_user(current_user.id) return redirect(url_for("index")) - @app.route('/accept-list', methods=['POST']) @login_required def accept_list(): @@ -841,7 +683,6 @@ def accept_list(): current_user.accept_List(habit_list.id) return {} - @app.route('/deny-list', methods=['POST']) @login_required def deny_list(): @@ -861,6 +702,153 @@ def deny_list(): habit_list.remove_user(current_user.id) return {} +########################################################### + + + +######################### Profile ######################### +@app.route('/profile') +@login_required +def profile(): + return render_template( + "profile.html", + name=current_user.name, + email=current_user.email, + profile_image_url=current_user.profile_image, + color = current_user.heatmap_color, + title="Profil", + ) + +@app.route('/profile', methods=['POST']) +@login_required +def profile_change(): + newName = request.form.get('newName') + newEmail = request.form.get('newEmail') + + # Update user + current_user.name = newName + current_user.email = newEmail + current_user.update() + + # Back to profile + return render_template( + "profile.html", + name=current_user.name, + email=current_user.email, + profile_image_url=current_user.profile_image, + color=current_user.heatmap_color, + ) + +@app.route('/check_password', methods=['POST']) +@login_required +def check_password(): + # Get the password sent from the client + password = request.json.get('password') + + if hashlib.sha256(password.encode()).hexdigest() == current_user.password: + return jsonify({"valid": True}) + else: + return jsonify({"valid": False}) + +@app.route('/password', methods=['POST']) +@login_required +def password_change(): + newPassword = request.form.get('newPassword') + + # Update user + if newPassword: + current_user.password = hashlib.sha256(newPassword.encode()).hexdigest() + current_user.update() + + # Back to profile + return render_template( + "profile.html", + name=current_user.name, + email=current_user.email, + profile_image_url=current_user.profile_image, + color=current_user.heatmap_color, + ) + +def save_profile_image(image_file): + filename = image_file.filename + if '.' not in filename: + # Ensure the filename has an extension + raise ValueError("Invalid filename") + + # Check if the file extension is allowed + allowed_extensions = {'jpg', 'jpeg', 'png', 'gif'} + file_extension = filename.rsplit('.', 1)[1].lower() + if file_extension not in allowed_extensions: + raise ValueError("Invalid file extension") + + # Get the filename from the image path saved in the user + filename = os.path.basename(current_user.profile_image) + image_path = os.path.join(app.config['UPLOAD_FOLDER'], filename) + os.remove(image_path) + + # Check if the image is an animated gif + if file_extension == 'gif': + gif_path = os.path.join(app.config['UPLOAD_FOLDER'], filename.replace(".jpg", ".gif")) + image_file.save(gif_path) + + current_user.profile_image = gif_path + current_user.update() + return + + # Open the uploaded image + image = Image.open(image_file) + + # Convert the image to RGB mode (required for JPEG) + image = image.convert('RGB') + + # Determine the size of the square image + min_dimension = min(image.size) + square_size = (min_dimension, min_dimension) + + # Calculate the coordinates for cropping + left = (image.width - min_dimension) / 2 + top = (image.height - min_dimension) / 2 + right = (image.width + min_dimension) / 2 + bottom = (image.height + min_dimension) / 2 + + # Crop the image to a square and resize it + image = image.crop((left, top, right, bottom)) + image.thumbnail(square_size) + image = image.resize((256, 256)) + + # Save the processed image + image_path = os.path.join(app.config['UPLOAD_FOLDER'], filename.replace(".gif", ".jpg")) + image.save(image_path, 'JPEG', quality=100) + current_user.profile_image = image_path + current_user.update() + +@app.route('/upload', methods=['POST']) +def upload_profile_image(): + if 'file' not in request.files: + return 'No file part' + + file = request.files['file'] + save_profile_image(file) + + # Back to profile + return redirect(url_for('profile')) + +@app.route('/save_color', methods=['POST']) +def save_heatmap_color(): + # Get the color value from the form + new_color = request.form['color'] + current_user.heatmap_color = new_color + current_user.update() + + # Back to profile + return render_template( + "profile.html", + name=current_user.name, + email=current_user.email, + profile_image_url=current_user.profile_image, + color=current_user.heatmap_color, + ) +########################################################### # Run the application