diff --git a/api/v1/routes/testimonial.py b/api/v1/routes/testimonial.py index 87820b736..015e44abd 100644 --- a/api/v1/routes/testimonial.py +++ b/api/v1/routes/testimonial.py @@ -7,7 +7,7 @@ from sqlalchemy.orm import Session from api.v1.models.user import User from fastapi import Depends, APIRouter, status,Query -from api.utils.success_response import success_response +from api.utils.success_response import success_response, fail_response from api.v1.services.testimonial import testimonial_service from api.v1.services.user import user_service from api.v1.schemas.testimonial import CreateTestimonial @@ -81,6 +81,7 @@ async def delete_all_testimonials( testimonial_service.delete_all(db) + @testimonial.post('/', response_model=success_response) def create_testimonial( testimonial_data: CreateTestimonial, @@ -96,35 +97,32 @@ def create_testimonial( ) return response -@testimonial.get("/user/{user_id}", status_code=status.HTTP_200_OK) -def get_user_testimonials( - user_id: str, - page_size: Annotated[int, Query(ge=1, description="Number of testimonials per page")] = 10, - page: Annotated[int, Query(ge=1, description="Page number (starts from 1)")] = 0, - db: Session = Depends(get_db), - current_user: User = Depends(user_service.get_current_user), + +@testimonial.put('/{testimonial_id}', response_model=success_response) +def update_testimonial( + testimonial_id: str, + testimonial_data: CreateTestimonial, + db: Annotated[Session, Depends(get_db)], + current_user: User = Depends(user_service.get_current_user) ): - """Endpoint to get all testimonials for a specific user with pagination""" - try: - # Only check if user is accessing their own testimonials - if user_id != str(current_user.id): - return { - "status_code": 403, - "message": "You can only view your own testimonials" - } - - # Simply return the paginated response - return paginated_response( - db=db, - model=Testimonial, - limit=page_size, - skip=max(page, 0), - filters={"author_id": user_id} + '''Endpoint to update testimonial''' + testimonial = testimonial_service.fetch(db, testimonial_id) + + if not testimonial: + return fail_response( + status_code=404, + message="Testimonial does not exist" + ) + + if testimonial.author_id != current_user.id: + return fail_response( + status_code=403, + message="Could not validate credentials" ) - - except Exception as e: - logger.exception(f"Error retrieving testimonials: {str(e)}") - return { - "status_code": 500, - "message": "An unexpected error occurred" - } + + update_testimonial = testimonial_service.update(db, testimonial_id, testimonial_data) + return success_response( + status_code=200, + message="Your testimonial has been updated successfully.", + data={"id": update_testimonial.id} + ) diff --git a/tests/v1/testimonial/test_create_testimonial.py b/tests/v1/testimonial/test_create_testimonial.py index 289b9ae4d..bd7a4248f 100644 --- a/tests/v1/testimonial/test_create_testimonial.py +++ b/tests/v1/testimonial/test_create_testimonial.py @@ -28,6 +28,11 @@ "content": "Testimonial 2", "status_code": 201, }, + { + "content": "I love python", + "ratings": 5.02, + "status_code": 201, + }, ] @pytest.fixture(scope='module') diff --git a/tests/v1/testimonial/test_update_testimonial.py b/tests/v1/testimonial/test_update_testimonial.py new file mode 100644 index 000000000..f52a403e0 --- /dev/null +++ b/tests/v1/testimonial/test_update_testimonial.py @@ -0,0 +1,155 @@ +import uuid +import pytest +from main import app +from fastapi.testclient import TestClient +from unittest.mock import MagicMock, patch +from api.v1.models import Testimonial # noqa: F403 + +client = TestClient(app) + +data = [ + { + "client_name": "firsttestclientname", + "author_id": "066a16d8-cab5-7dd3-8000-3a167556bb49", + "content": "I love python", + "id": "066a6e8b-f008-7242-8000-8f090997097c", + "updated_at": "2025-03-01T01:56:31.002967+01:00", + "client_designation": "testclient", + "comments": "I love testimonies", + "ratings": 5.02, + "created_at": "2025-01-01T01:56:31.002967+01:00", + } +] + + +@pytest.fixture(scope='module') +def mock_send_mail(): + """ For mocking the email send functionality """ + with patch("api.core.dependencies.email_sender.send_email") as mock_email_sending: + with patch("fastapi.BackgroundTasks.add_task") as add_task_mock: + add_task_mock.side_effect = lambda func, *args, **kwargs: func(*args, **kwargs) + yield mock_email_sending + + +@pytest.fixture(scope="function") +def client_with_mocks(mock_send_mail): + """For mocking a database connection and returning a test client""" + with patch('api.db.database.get_db') as mock_get_db: + mock_db = MagicMock() + mock_get_db.return_value = mock_db + + mock_db.query.return_value.filter.return_value.first.return_value = None + mock_db.add.reset_mock() + mock_db.commit.reset_mock() + mock_db.refresh.reset_mock() + + yield client, mock_db + +@pytest.fixture(autouse=True) +def setup_access_token(client_with_mocks): + """For setting up an access token for authentication""" + client, mock_db = client_with_mocks + mock_db.query.return_value.filter.return_value.first.return_value = None + + email = f"test{uuid.uuid4()}@gmail.com" + user_response = client.post( + "/api/v1/auth/register", + json={ + "password": "@Testpassword2", + "confirm_password": "@Testpassword2", + "first_name": "Test", + "last_name": "User", + "email": email, + }, + ) + assert user_response.status_code == 201, f"Setup failed: {user_response.json()}" + return user_response.json()["data"]["access_token"] + + +def test_create_testimonial(client_with_mocks, setup_access_token): + """Test to create testimonial""" + client, mock_db = client_with_mocks + + payload = { + "content": "I love python", + "ratings": 5.02, + } + + response = client.post( + "api/v1/testimonials/", + json=payload, + headers={"Authorization": setup_access_token}, + ) + + assert response.status_code == 201 + + testimonial_id = response.json()["data"]["id"] + testimonial = MagicMock() + testimonial.content = payload["content"] + testimonial.ratings = payload["ratings"] + + mock_db.query(Testimonial).get.return_value = testimonial + retrieved_testimonial = mock_db.query(Testimonial).get(testimonial_id) + + assert retrieved_testimonial.content == payload["content"] + assert retrieved_testimonial.ratings == payload["ratings"] + + return testimonial_id + + +def test_update_testimonial_success(client_with_mocks, setup_access_token): + """Test to update testimonial successfully""" + client, mock_db = client_with_mocks + + testimonial_id = test_create_testimonial(client_with_mocks, setup_access_token) + + mock_testimonial = MagicMock() + mock_testimonial.id = uuid.UUID(testimonial_id) + mock_testimonial.content = data[0]["content"] + mock_testimonial.client_name = data[0]["client_name"] + mock_testimonial.client_designation = data[0]["client_designation"] + mock_testimonial.comments = data[0]["comments"] + mock_testimonial.ratings = data[0]["ratings"] + + mock_db.query.return_value.filter.return_value.first.return_value = mock_testimonial + + update_data = {"content": "I love python (updated)"} + + response = client.put( + f"/api/v1/testimonials/{data[0]['id']}", + json=update_data, + headers={"Authorization": setup_access_token}, + ) + + assert response.status_code == 200, f"Expected 200, got {response.status_code}: {response.json()}" + assert response.json()["message"] == "Your testimonial has been updated successfully." + + +def test_update_testimonial_not_found(client_with_mocks, setup_access_token): + """Test to update testimonial that does not exist""" + client, mock_db = client_with_mocks + + mock_db.query.return_value.filter.return_value.first.return_value = None + + response = client.put( + "/api/v1/testimonials/non_existent_id", + json={"content": "This is an updated testimonial."}, + headers={"Authorization": f"Bearer {setup_access_token}"}, + ) + + assert response.status_code == 404 + assert response.json()["message"] == "Testimonial does not exist" + + +def test_update_testimonial_unauthorized(client_with_mocks): + """Test to update testimonial without authorization""" + client, _ = client_with_mocks + + response = client.put( + f"/api/v1/testimonials/{data[0]['id']}", + json={"content": "This is an updated testimonial."}, + headers={"Authorization": "Bearer invalid_token"}, + ) + + assert response.status_code == 401 + assert response.json()["message"] == "Could not validate credentials"