Skip to content

Commit

Permalink
Merge branch 'dev' into DrInTech
Browse files Browse the repository at this point in the history
  • Loading branch information
DrInTech22 authored Aug 24, 2024
2 parents 2661d52 + 5178826 commit ac3005c
Show file tree
Hide file tree
Showing 5 changed files with 249 additions and 19 deletions.
32 changes: 30 additions & 2 deletions api/v1/routes/blog.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from api.utils.pagination import paginated_response
from api.utils.success_response import success_response
from api.v1.models.user import User
from api.v1.models.blog import Blog, BlogDislike, BlogLike
from api.v1.models.blog import Blog
from api.v1.schemas.blog import (
BlogCreate,
BlogPostResponse,
Expand All @@ -20,7 +20,7 @@
CommentRequest,
CommentUpdateResponseModel
)
from api.v1.services.blog import BlogService
from api.v1.services.blog import BlogService, BlogDislikeService
from api.v1.services.user import user_service
from api.v1.schemas.comment import CommentCreate, CommentSuccessResponse
from api.v1.services.comment import comment_service
Expand Down Expand Up @@ -118,6 +118,7 @@ def like_blog_post(
current_user: User = Depends(user_service.get_current_user),
):
"""Endpoint to add `like` to a blog post.
Existing `dislike` by the `current_user` is automatically deleted.
args:
blog_id: `str` The ID of the blog post.
Expand All @@ -137,6 +138,9 @@ def like_blog_post(
# confirm current user has NOT liked before
blog_service.check_user_already_liked_blog(blog_p, current_user)

# check for BlogDislike by current user and delete it
blog_service.delete_opposite_blog_like_or_dislike(blog_p, current_user, "like")

# update likes
new_like = blog_service.create_blog_like(
db, blog_p.id, current_user.id, ip_address=get_ip_address(request))
Expand All @@ -160,6 +164,7 @@ def dislike_blog_post(
current_user: User = Depends(user_service.get_current_user),
):
"""Endpoint to add `dislike` to a blog post.
Existing `like` by the `current_user` is automatically deleted.
args:
blog_id: `str` The ID of the blog post.
Expand All @@ -179,6 +184,9 @@ def dislike_blog_post(
# confirm current user has NOT disliked before
blog_service.check_user_already_disliked_blog(blog_p, current_user)

# check for BlogLike by current user and delete it
blog_service.delete_opposite_blog_like_or_dislike(blog_p, current_user, "dislike")

# update disikes
new_dislike = blog_service.create_blog_dislike(
db, blog_p.id, current_user.id, ip_address=get_ip_address(request))
Expand Down Expand Up @@ -299,3 +307,23 @@ async def update_blog_comment(
status_code=200,
data=jsonable_encoder(updated_blog_comment)
)


@blog.delete("/dislikes/{blog_dislike_id}",
status_code=status.HTTP_204_NO_CONTENT)
def delete_blog_dislike(
blog_dislike_id: str,
db: Session = Depends(get_db),
current_user: User = Depends(user_service.get_current_user),
):
"""Endpoint to delete `BlogDislike`
args:
blog_dislike_id: `str` The ID of the BlogDislike object.
request: `default` Request.
db: `default` Session.
"""
blog_dislike_service = BlogDislikeService(db)

# delete blog dislike
return blog_dislike_service.delete(blog_dislike_id, current_user.id)
27 changes: 15 additions & 12 deletions api/v1/routes/newsletter.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,20 +37,23 @@ async def sub_newsletter(
# Save user to the database
NewsletterService.create(db, request)

link = "https://anchor-python.teams.hng.tech/"

# Send email in the background
background_tasks.add_task(
send_email,
recipient=request.email,
template_name="newsletter-subscription.html",
subject="Thank You for Subscribing to HNG Boilerplate Newsletters",
context={"link": link},
)
link = "https://anchor-python.teams.hng.tech/"

# Send email in the background
background_tasks.add_task(
send_email,
recipient=request.email,
template_name="newsletter-subscription.html",
subject="Thank You for Subscribing to HNG Boilerplate Newsletters",
context={"link": link},
)
message = "Thank you for subscribing to our newsletter."
else:
message = "You have already subscribed to our newsletter. Thank you."

return success_response(
message="Thank you for subscribing to our newsletter.",
status_code=status.HTTP_201_CREATED,
message=message,
status_code=status.HTTP_200_OK,
)


Expand Down
56 changes: 54 additions & 2 deletions api/v1/services/blog.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,21 +118,48 @@ def fetch_blog_dislike(self, blog_id: str, user_id: str):
)
return blog_dislike

def check_user_already_liked_blog(self, blog: Blog, user: Blog):
def check_user_already_liked_blog(self, blog: Blog, user: User):
existing_like = self.fetch_blog_like(blog.id, user.id)
if isinstance(existing_like, BlogLike):
raise HTTPException(
detail="You have already liked this blog post",
status_code=status.HTTP_403_FORBIDDEN,
)

def check_user_already_disliked_blog(self, blog: Blog, user: Blog):
def check_user_already_disliked_blog(self, blog: Blog, user: User):
existing_dislike = self.fetch_blog_dislike(blog.id, user.id)
if isinstance(existing_dislike, BlogDislike):
raise HTTPException(
detail="You have already disliked this blog post",
status_code=status.HTTP_403_FORBIDDEN,
)

def delete_opposite_blog_like_or_dislike(self, blog: Blog, user: User, creating: str):
"""
This method checks if there's a BlogLike by `user` on `blog` when a BlogDislike
is being created and deletes the BlogLike. The same for BlogLike creation. \n
:param blog: `Blog` The blog being liked or disliked
:param user: `User` The user liking or disliking the blog
:param creating: `str` The operation being performed by the user. One of "like", "dislike"
"""
if creating == "like":
existing_dislike = self.fetch_blog_dislike(blog.id, user.id)
if existing_dislike:
# delete, but do not commit yet. Allow everything
# to be commited after the actual like is created
self.db.delete(existing_dislike)
elif creating == "dislike":
existing_like = self.fetch_blog_like(blog.id, user.id)
if existing_like:
# delete, but do not commit yet. Allow everything
# to be commited after the actual dislike is created
self.db.delete(existing_like)
else:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="Invalid `creating` value for blog like/dislike"
)

def num_of_likes(self, blog_id: str) -> int:
"""Get the number of likes a blog post has"""
Expand Down Expand Up @@ -211,3 +238,28 @@ def update_blog_comment(
)

return comment


class BlogDislikeService:
"""BlogDislike service functionality"""

def __init__(self, db: Session):
self.db = db

def fetch(self, blog_dislike_id: str):
"""Fetch a blog dislike by its ID"""
return check_model_existence(self.db, BlogDislike, blog_dislike_id)

def delete(self, blog_dislike_id: str, user_id: str):
"""Delete blog dislike"""
blog_dislike = self.fetch(blog_dislike_id)

# check that current user owns the blog like
if blog_dislike.user_id != user_id:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Insufficient permission"
)

self.db.delete(blog_dislike)
self.db.commit()
11 changes: 8 additions & 3 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ alembic==1.13.2
annotated-types==0.7.0
anyio==4.4.0
astroid==3.2.4
async-timeout==4.0.3
attrs==23.2.0
Authlib==1.3.1
autopep8==2.3.1
Expand All @@ -23,6 +24,7 @@ colorama==0.4.6
cryptography==43.0.0
cssselect==1.2.0
cssutils==2.11.1
Deprecated==1.2.14
dill==0.3.8
distlib==0.3.8
dnspython==2.6.1
Expand All @@ -37,17 +39,18 @@ filelock==3.15.4
flake8==7.1.0
frozenlist==1.4.1
greenlet==3.0.3
slowapi==0.1.9
h11==0.14.0
httpcore==1.0.5
httptools==0.6.1
httpx==0.27.0
identify==2.6.0
idna==3.7
importlib_resources==6.4.4
iniconfig==2.0.0
isort==5.13.2
itsdangerous==2.2.0
Jinja2==3.1.4
limits==3.13.0
lxml==5.2.2
Mako==1.3.5
markdown-it-py==3.0.0
Expand All @@ -61,8 +64,8 @@ nodeenv==1.9.1
packaging==24.1
passlib==1.7.4
pathspec==0.12.1
pillow==10.4.0
pipdeptree==2.23.1
Pillow==10.4.0
platformdirs==4.2.2
pluggy==1.5.0
pre-commit==3.7.1
Expand Down Expand Up @@ -94,9 +97,11 @@ rich==13.7.1
rsa==4.9
shellingham==1.5.4
six==1.16.0
slowapi==0.1.9
sniffio==1.3.1
SQLAlchemy==2.0.31
starlette==0.37.2
stripe==10.7.0
tomli==2.0.1
tomlkit==0.13.0
twilio==9.2.3
Expand All @@ -110,5 +115,5 @@ virtualenv==20.26.3
watchfiles==0.22.0
webencodings==0.5.1
websockets==12.0
wrapt==1.16.0
yarl==1.9.4
stripe==10.7.0
Loading

0 comments on commit ac3005c

Please sign in to comment.