Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: delete blog like #967

Merged
merged 6 commits into from
Aug 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 21 additions & 1 deletion api/v1/routes/blog.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
CommentRequest,
CommentUpdateResponseModel
)
from api.v1.services.blog import BlogService, BlogDislikeService
from api.v1.services.blog import BlogService, BlogDislikeService, BlogLikeService
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 @@ -309,6 +309,26 @@ async def update_blog_comment(
)


@blog.delete("/likes/{blog_like_id}",
status_code=status.HTTP_204_NO_CONTENT)
async def delete_blog_like(
blog_like_id: str,
db: Session = Depends(get_db),
current_user: User = Depends(user_service.get_current_user),
):
"""Endpoint to delete `BlogLike`

args:
blog_like_id: `str` The ID of the BlogLike object.
request: `default` Request.
db: `default` Session.
"""
blog_like_service = BlogLikeService(db)

# delete blog like
return blog_like_service.delete(blog_like_id, current_user.id)
johnson-oragui marked this conversation as resolved.
Show resolved Hide resolved


@blog.delete("/dislikes/{blog_dislike_id}",
status_code=status.HTTP_204_NO_CONTENT)
def delete_blog_dislike(
Expand Down
25 changes: 25 additions & 0 deletions api/v1/services/blog.py
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,31 @@ def update_blog_comment(
return comment


class BlogLikeService:
"""BlogLike service functionality"""

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

def fetch(self, blog_like_id: str):
"""Fetch a blog like by its ID"""
return check_model_existence(self.db, BlogLike, blog_like_id)

def delete(self, blog_like_id: str, user_id: str):
"""Delete blog like"""
blog_like = self.fetch(blog_like_id)

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

self.db.delete(blog_like)
self.db.commit()
johnson-oragui marked this conversation as resolved.
Show resolved Hide resolved


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

Expand Down
144 changes: 144 additions & 0 deletions tests/v1/blog/test_delete_blog_like.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
import pytest
from main import app
from uuid_extensions import uuid7
from sqlalchemy.orm import Session
from api.db.database import get_db
from datetime import datetime, timezone
from api.v1.models import User, BlogLike
from fastapi.testclient import TestClient
from unittest.mock import patch, MagicMock
from api.v1.services.user import user_service

client = TestClient(app)

# Mock database
@pytest.fixture
def mock_db_session(mocker):
db_session_mock = mocker.MagicMock(spec=Session)
app.dependency_overrides[get_db] = lambda: db_session_mock
return db_session_mock


@pytest.fixture
def mock_user_service():
with patch("api.v1.services.user.user_service", autospec=True) as user_service_mock:
yield user_service_mock


@pytest.fixture
def mock_blog_service():
with patch("api.v1.services.blog.BlogService", autospec=True) as blog_service_mock:
yield blog_service_mock


# Test User
@pytest.fixture
def test_user():
return User(
id=str(uuid7()),
email="[email protected]",
password="hashedpassword",
first_name="test",
last_name="user",
is_active=True,
)


# Another User
@pytest.fixture
def another_user():
return User(
id=str(uuid7()),
email="[email protected]",
password="hashedpassword",
first_name="another",
last_name="user",
is_active=True,
)

@pytest.fixture
def test_blog_like(test_user):
return BlogLike(
id=str(uuid7()),
user_id=test_user.id,
blog_id=str(uuid7()),
ip_address="192.168.1.0",
created_at=datetime.now(tz=timezone.utc)
)

@pytest.fixture
def access_token_user(test_user):
return user_service.create_access_token(user_id=test_user.id)

@pytest.fixture
def access_token_another(another_user):
return user_service.create_access_token(user_id=another_user.id)


def make_request(blog_like_id, token):
return client.delete(
f"/api/v1/blogs/likes/{blog_like_id}",
headers={"Authorization": f"Bearer {token}"}
)


# test for successful delete
@patch("api.v1.services.blog.BlogLikeService.fetch")
def test_successful_delete_bloglike(
mock_fetch_blog_like,
mock_db_session,
test_user,
test_blog_like,
access_token_user
):
# mock current-user AND blog-like
mock_db_session.query().filter().first.return_value = test_user
mock_fetch_blog_like.return_value = test_blog_like

resp = make_request(test_blog_like.id, access_token_user)
assert resp.status_code == 204


# Test for wrong blog like id
def test_wrong_blog_like_id(
# mock_fetch_blog_like,
mock_db_session,
test_user,
access_token_user,
):
mock_db_session.query().filter().first.return_value = test_user
mock_db_session.get.return_value = None

### TEST REQUEST WITH WRONG blog_like_id ###
resp = make_request(str(uuid7()), access_token_user)
assert resp.status_code == 404
assert resp.json()['message'] == "BlogLike does not exist"


# Test for unauthenticated user
def test_wrong_auth_token(
mock_db_session,
test_blog_like
):
mock_user_service.get_current_user = None

### TEST ATTEMPT WITH INVALID AUTH ###
resp = make_request(test_blog_like.id, None)
assert resp.status_code == 401
assert resp.json()['message'] == 'Could not validate credentials'


# Test for wrong owner request
def test_wrong_owner_request(
mock_db_session,
test_blog_like,
another_user,
access_token_another
):
mock_user_service.get_current_user = another_user
mock_db_session.get.return_value = test_blog_like

### TEST ATTEMPT BY NON OWNER ###
resp = make_request(test_blog_like.id, access_token_another)
assert resp.status_code == 401
assert resp.json()['message'] == 'Insufficient permission'
Loading