Skip to content

Commit

Permalink
[Updates📢] Added comments to recipes
Browse files Browse the repository at this point in the history
  • Loading branch information
[esekyi] committed Sep 4, 2024
1 parent f4f91f5 commit f295a62
Show file tree
Hide file tree
Showing 5 changed files with 344 additions and 83 deletions.
2 changes: 2 additions & 0 deletions app/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@

login_manager = LoginManager()
login_manager.login_view = 'auth.login'
login_manager.login_message = 'You Must Login to Access This Page!'
login_manager.login_message_category = 'error'

# initializing db extensions
db = SQLAlchemy()
Expand Down
132 changes: 119 additions & 13 deletions app/routes/recipe_routes.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
from flask import Blueprint, request, url_for, render_template, flash, redirect
from app import db
from app.services.recipe_service import get_all_recipes, get_recipe_by_id, create_recipe, get_most_viewed_recipes
from app.services.recipe_service import get_all_recipes, get_recipe_by_id, create_recipe, get_most_viewed_recipes, update_recipe, delete_recipe, get_recipe_with_details
from app.services.validation_service import validate_recipe_data
from app.services.category_service import CategoryService
from app.services.image_service import upload_image_to_s3
from app.services.image_service import upload_image_to_s3, delete_image_from_s3
from app.services.comment_service import CommentService
from flask_login import login_required, current_user
from app.models.user import User
from app.models.comment import Comment
import os

bp = Blueprint('recipe_routes', __name__)

# s3_url = f"https://{os.getenv('S3_BUCKET_NAME')}.s3{os.getenv('AWS_REGION')}.amazonaws.com/"


@bp.route('/recipes/create', methods=['GET', 'POST'], strict_slashes=False)
@login_required
Expand Down Expand Up @@ -76,28 +76,134 @@ def list_recipes():
title='Recipes | SpiceShare Inc.')


@bp.route('/recipes/<uuid:recipe_id>', methods=['GET'], strict_slashes=False)
@bp.route('/recipes/<uuid:recipe_id>', methods=['GET', 'POST'], strict_slashes=False)
def view_recipe(recipe_id):
recipe = get_recipe_by_id(recipe_id)
recipe.view_count += 1
db.session.commit()
recipe, ingredients, instructions = get_recipe_with_details(recipe_id)
comments = CommentService.get_comment_by_recipe(recipe_id) # Fetch comments for the recipe

return render_template('recipes/readPages/recipe_detail.html', recipe=recipe, title=f'{recipe.title} - SpiceShare Inc.')
# Fetch user details for each comment
for comment in comments:
comment.user = db.session.query(User).filter_by(id=comment.user_id).first() # Get the user who made the comment

if recipe:
recipe.view_count += 1
db.session.commit()
recipe.user = db.session.query(User).filter_by(id=recipe.user_id).first()
return render_template('recipes/readPages/recipe_detail.html', recipe=recipe, ingredients=ingredients, instructions=instructions, comments=comments, title=f'{recipe.title} - SpiceShare Inc.')
else:
flash("Recipe not found.", "error")
return redirect(url_for('recipe_routes.list_recipes'))


@bp.route('/recipes/<uuid:recipe_id>/edit', methods=['PUT'], strict_slashes=False)
@bp.route('/recipes/<uuid:recipe_id>/edit', methods=['GET', 'POST'], strict_slashes=False)
@login_required
def edit_recipe(recipe_id):
pass
recipe, ingredients, instructions = get_recipe_with_details(recipe_id)

if request.method == 'POST':
if recipe and recipe.user_id == current_user.id:
data = request.form.to_dict()
ingredients = request.form.getlist('ingredients[]')
instructions = request.form.getlist('instructions[]')
image = request.files.get('image')

errors = validate_recipe_data(data)
if errors:
for error in errors:
flash(error, 'error')
return redirect(url_for('recipe_routes.add_recipe', recipe_id=recipe_id))

image_url = recipe.image_url
if image:
try:
image_url = upload_image_to_s3(image)
flash("Image updated successfully", "succes")
except ValueError as e:
flash(str(e), 'error')
return redirect(url_for('recipe_routes.edit_recipe', recipe_id=recipe_id))

try:
update_recipe(recipe, data, ingredients,
instructions, image_url)
flash(
f"Recipe {recipe.title} updated successfully!", 'success')
return redirect(url_for('recipe_routes.view_recipe', recipe_id=recipe_id))

except Exception as e:
# Rollback db session in case of an error
db.session.rollback()
flash(
f"An error occurred while creating the recipe: {str(e)}", "error")
return redirect(url_for('recipe_routes.edit_recipe', recipe_id=recipe_id))

@bp.route('/recipes/<uuid:recipe_id>/delete', methods=['DELETE'], strict_slashes=False)
categories = CategoryService.get_all_categories()
return render_template('recipes/createPages/edit1.html', recipe=recipe, ingredients=ingredients, instructions=instructions, categories=categories, title=f'Edit Recipe {recipe.title} | SpiceShare Inc.')


@bp.route('/recipes/<uuid:recipe_id>/delete', methods=['POST'], strict_slashes=False)
@login_required
def remove_recipe(recipe_id):
pass
recipe = get_recipe_by_id(recipe_id)

if recipe and recipe.user_id == current_user.id:
try:
if recipe.image_url:
if delete_image_from_s3(recipe.image_url):
flash("Image deleted", 'success')
else:
flash("Failed to delet Image", 'info')

delete_recipe(recipe)
flash("Recipe deleted successfully!", 'info')
return redirect(url_for('recipe_routes.recipe_list'))

except Exception as e:
flash(
f"An error occured while deleting the recipe: {str(e)}", "error")
else:

flash("Unauthorized action.", 'error')
return redirect(url_for('recipe_routes.list_recipes'))


@bp.route('/most_viewed', methods=['GET'], strict_slashes=False)
def most_viewed():
recipes = get_most_viewed_recipes(limit=5) # adjust with preferred limit default 5
return recipes


@bp.route('/recipes/<uuid:recipe_id>/comments', methods=['POST'])
@login_required
def add_comment(recipe_id):
text = request.form.get('text')
if text:
comment = CommentService.add_comment(recipe_id, current_user.id, text)
flash("Comment added successfully!", "success")
else:
flash("Comment cannot be empty.", "info")
return redirect(url_for('recipe_routes.view_recipe', recipe_id=recipe_id))


@bp.route('/comments/<uuid:comment_id>/update', methods=['POST'])
@login_required
def update_comment(comment_id):
text = request.form.get('text')
comment = CommentService.update_comment(
comment_id, current_user.id, text) # Pass current_user.id
if comment:
flash("Comment updated successfully!", "success")
else:
flash("Comment not found or you are not authorized to update it.", "error")
return redirect(url_for('recipe_routes.view_recipe', recipe_id=comment.recipe_id))


@bp.route('/comments/<uuid:comment_id>/delete', methods=['POST'])
@login_required
def delete_comment(comment_id):
# Pass current_user.id
comment = Comment.query.get_or_404(comment_id)
if CommentService.delete_comment(comment_id, current_user.id):
flash("Comment deleted successfully!", "info")
else:
flash("Comment not found or you are not authorized to delete it.", "error")
return redirect(url_for('recipe_routes.view_recipe', recipe_id=comment.recipe_id))
37 changes: 37 additions & 0 deletions app/services/comment_service.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
from app import db
from app.models.comment import Comment

class CommentService:
@staticmethod
def add_comment(recipe_id, user_id, text):
"""Add a comment to a recipe."""
new_comment = Comment(recipe_id=recipe_id, user_id=user_id, text=text)
db.session.add(new_comment)
db.session.commit()
return new_comment


@staticmethod
def get_comment_by_recipe(recipe_id):
"""Retrieve all comments for a given recipe."""
return Comment.query.filter_by(recipe_id=recipe_id).order_by(Comment.created_at.desc()).all()


@staticmethod
def update_comment(comment_id, user_id, text):
"""Updates a comments."""
comment = Comment.query.get_or_404(comment_id)
if comment and comment.user_id == user_id:
comment.text = text
db.session.commit()
return comment
return None

@staticmethod
def delete_comment(comment_id, user_id):
comment = Comment.query.get_or_404(comment_id)
if comment and comment.user_id == user_id:
db.session.delete(comment)
db.session.commit()
return True
return False
47 changes: 44 additions & 3 deletions app/services/image_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
from flask import current_app
import uuid
from werkzeug.utils import secure_filename
import logging # Add this import at the top
import logging

# Configure logging
logging.basicConfig(level=logging.DEBUG) # Set the logging level to DEBUG
logging.basicConfig(level=logging.DEBUG) # logging level to DEBUG



Expand All @@ -17,7 +17,6 @@ def upload_image_to_s3(image, folder='recipes'):
aws_secret_access_key = current_app.config['S3_SECRET_ACCESS_KEY']
region_name = current_app.config['S3_REGION']
bucket_name = current_app.config['S3_BUCKET_NAME']

try:

# Generating a random and unique filename for image
Expand Down Expand Up @@ -57,3 +56,45 @@ def upload_image_to_s3(image, folder='recipes'):
except Exception as e:
logging.error(f"An unexpected error occurred: {e}")
raise ValueError(f"An unexpected error occurred: {e}")


def delete_image_from_s3(image_filename, folder='recipes'):
"""
Deletes an image from the S3 bucket.
:param image_filename: The filename of the image to be deleted.
:return: True if the file was deleted, False if the file was not found or deletion failed.
"""

aws_access_key_id = current_app.config['S3_ACCESS_KEY_ID']
aws_secret_access_key = current_app.config['S3_SECRET_ACCESS_KEY']
region_name = current_app.config['S3_REGION']
bucket_name = current_app.config['S3_BUCKET_NAME']

try:
s3_client = boto3(
's3',
aws_access_key_id=aws_access_key_id,
aws_secret_access_key=aws_secret_access_key,
region_name=region_name
)


# Delete the file from S3
response = s3_client.delete_object(
Bucket=bucket_name,
Key=f"{folder}/{image_filename}"
)

if response.get('ResponseMetadata', {}).get('HTTPStatusCode') == 204:
return True
else:
return False


except ClientError as e:
logging.error(f"Failed to delete image: {e}")
return False
except Exception as e:
logging.error(f"An unexpected error occurred: {e}")
return False
Loading

0 comments on commit f295a62

Please sign in to comment.