Skip to content

Commit b27e354

Browse files
authored
Merge pull request #1192 from eniiku/feat/update_squeezepage_endpoint
feat: update squeeze-page endpoint
2 parents 3407c89 + adf721d commit b27e354

4 files changed

Lines changed: 233 additions & 22 deletions

File tree

api/v1/routes/squeeze.py

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
1-
from fastapi import APIRouter, Depends, status, BackgroundTasks
1+
from fastapi import APIRouter, BackgroundTasks, Depends, HTTPException, status
22
from sqlalchemy.orm import Session
3-
from api.db.database import get_db
3+
44
from api.core.responses import SUCCESS
5+
from api.db.database import get_db
56
from api.utils.success_response import success_response
7+
from api.v1.models import *
8+
from api.v1.schemas.squeeze import CreateSqueeze, FilterSqueeze, UpdateSqueeze
69
from api.v1.services.squeeze import squeeze_service
7-
from api.v1.schemas.squeeze import CreateSqueeze, FilterSqueeze
810
from api.v1.services.user import user_service
9-
from api.v1.models import *
1011

1112
squeeze = APIRouter(prefix="/squeeze", tags=["Squeeze Page"])
1213

@@ -52,7 +53,34 @@ def get_squeeze(
5253
return success_response(status.HTTP_404_NOT_FOUND, "Squeeze page not found!")
5354
return success_response(status.HTTP_200_OK, SUCCESS, squeeze_page)
5455

56+
5557
@squeeze.delete("/{squeeze_id}", status_code=status.HTTP_204_NO_CONTENT)
56-
def delete_squeeze(squeeze_id: str, db: Session = Depends(get_db), current_user: User = Depends(user_service.get_current_super_admin)):
58+
def delete_squeeze(
59+
squeeze_id: str,
60+
db: Session = Depends(get_db),
61+
current_user: User = Depends(user_service.get_current_super_admin),
62+
):
5763
"""Delete a squeeze page"""
58-
squeeze_service.delete(db, squeeze_id)
64+
squeeze_service.delete(db, squeeze_id)
65+
66+
67+
@squeeze.put(
68+
"/{squeeze_id}", response_model=success_response, status_code=status.HTTP_200_OK
69+
)
70+
def update_squeeze(
71+
squeeze_id: str,
72+
data: UpdateSqueeze,
73+
db: Session = Depends(get_db),
74+
authorized_user: User = Depends(user_service.get_current_super_admin),
75+
):
76+
"""Update a squeeze page"""
77+
78+
if not authorized_user:
79+
raise HTTPException(status_code=401, detail="You are not Authorized")
80+
81+
updated_squeeze = squeeze_service.update(db, squeeze_id, data)
82+
return success_response(
83+
status.HTTP_200_OK,
84+
"Squeeze page updated successfully",
85+
updated_squeeze.to_dict(),
86+
)

api/v1/schemas/squeeze.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
1-
from pydantic import BaseModel, EmailStr
21
from enum import Enum
2+
from typing import Optional
3+
4+
from pydantic import BaseModel, EmailStr
5+
36

47
class SqueezeStatusEnum(str, Enum):
58
online = "online"
@@ -21,3 +24,13 @@ class CreateSqueeze(BaseModel):
2124

2225
class FilterSqueeze(BaseModel):
2326
status: SqueezeStatusEnum = None
27+
28+
29+
class UpdateSqueeze(BaseModel):
30+
title: Optional[str] = None
31+
headline: Optional[str] = None
32+
sub_headline: Optional[str] = None
33+
body: Optional[str] = None
34+
type: Optional[str] = None
35+
status: Optional[SqueezeStatusEnum] = None
36+
full_name: Optional[str] = None

api/v1/services/squeeze.py

Lines changed: 34 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
1-
from fastapi import HTTPException, BackgroundTasks
1+
from fastapi import BackgroundTasks, HTTPException
22
from sqlalchemy.orm import Session
3+
34
from api.core.base.services import Service
4-
from api.v1.models.squeeze import Squeeze
55
from api.core.dependencies.email_sender import send_email
6-
from api.v1.schemas.squeeze import CreateSqueeze, FilterSqueeze
6+
from api.v1.models.squeeze import Squeeze
7+
from api.v1.schemas.squeeze import CreateSqueeze, FilterSqueeze, UpdateSqueeze
78

89

910
class SqueezeService(Service):
1011
"""Squeeze service"""
1112

12-
def create(self, background_tasks: BackgroundTasks, db: Session, data: CreateSqueeze):
13+
def create(
14+
self, background_tasks: BackgroundTasks, db: Session, data: CreateSqueeze
15+
):
1316
"""Create squeeze page"""
1417
new_squeeze = Squeeze(
1518
title=data.title,
@@ -26,16 +29,13 @@ def create(self, background_tasks: BackgroundTasks, db: Session, data: CreateSqu
2629
db.add(new_squeeze)
2730
db.commit()
2831
db.refresh(new_squeeze)
29-
cta_link = 'https://anchor-python.teams.hng.tech/about-us'
32+
cta_link = "https://anchor-python.teams.hng.tech/about-us"
3033
background_tasks.add_task(
31-
send_email,
34+
send_email,
3235
recipient=data.email,
33-
template_name='squeeze.html',
34-
subject='Welcome to HNG Squeeze',
35-
context={
36-
'name': data.full_name,
37-
'cta_link': cta_link
38-
}
36+
template_name="squeeze.html",
37+
subject="Welcome to HNG Squeeze",
38+
context={"name": data.full_name, "cta_link": cta_link},
3939
)
4040

4141
return new_squeeze
@@ -62,17 +62,36 @@ def fetch(self, db: Session, id: str, filter: FilterSqueeze = None):
6262
squeeze = db.query(Squeeze).filter(Squeeze.id == id).first()
6363
return squeeze
6464

65-
def update(self, db: Session, id: str, schema):
65+
def update(self, db: Session, id: str, data: UpdateSqueeze):
6666
"""Update a specific squeeze page"""
67-
pass
67+
squeeze = db.query(Squeeze).filter(Squeeze.id == id).first()
68+
69+
if not squeeze:
70+
raise HTTPException(status_code=404, detail="Squeeze page not found")
71+
72+
# Update only the fields that are provided in the update data
73+
for field, value in data.dict(exclude_unset=True).items():
74+
setattr(squeeze, field, value)
75+
76+
try:
77+
db.commit()
78+
db.refresh(squeeze)
79+
except Exception as e:
80+
db.rollback()
81+
raise HTTPException(
82+
status_code=500,
83+
detail=f"Unexpected error occurred while updating the squeeze page: {e}",
84+
)
85+
86+
return squeeze
6887

6988
def delete(self, db: Session, id: str):
7089
"""Delete a specific squeeze page"""
7190
squeeze = db.query(Squeeze).filter(Squeeze.id == id).first()
7291

7392
if not squeeze:
7493
raise HTTPException(status_code=404, detail="Squeeze page not found")
75-
94+
7695
db.delete(squeeze)
7796
db.commit()
7897
db.refresh()
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
from datetime import datetime, timezone
2+
from unittest.mock import MagicMock
3+
4+
import pytest
5+
from fastapi.testclient import TestClient
6+
from sqlalchemy.orm import Session
7+
from uuid_extensions import uuid7
8+
9+
from api.db.database import get_db
10+
from api.v1.models.squeeze import Squeeze
11+
from api.v1.models.user import User
12+
from api.v1.schemas.squeeze import UpdateSqueeze
13+
from api.v1.services.user import user_service
14+
from main import app
15+
16+
17+
@pytest.fixture(scope="module")
18+
def client():
19+
with TestClient(app) as c:
20+
yield c
21+
22+
23+
@pytest.fixture
24+
def mock_db_session():
25+
db = MagicMock(spec=Session)
26+
yield db
27+
28+
29+
@pytest.fixture
30+
def mock_user():
31+
return User(
32+
id=f"{uuid7()}",
33+
email="test@example.com",
34+
password="hashedpassword1",
35+
first_name="test",
36+
last_name="user",
37+
created_at=datetime.now(timezone.utc),
38+
updated_at=datetime.now(timezone.utc),
39+
)
40+
41+
42+
@pytest.fixture()
43+
def mock_get_current_admin():
44+
return User(
45+
id=str(uuid7()),
46+
email="admin@gmail.com",
47+
password=user_service.hash_password("Testadmin@123"),
48+
first_name="Admin",
49+
last_name="User",
50+
is_active=True,
51+
is_superadmin=True,
52+
created_at=datetime.now(timezone.utc),
53+
updated_at=datetime.now(timezone.utc),
54+
)
55+
56+
57+
@pytest.fixture
58+
def valid_squeeze():
59+
return UpdateSqueeze(
60+
title="Updated Squeeze Page", headline="This is the new headline"
61+
)
62+
63+
64+
@pytest.fixture
65+
def exisiting_squeeze(mock_db_session):
66+
squeeze = Squeeze(
67+
id=str(uuid7()),
68+
title="My Squeeze Page",
69+
email="user1@example.com",
70+
headline="My Headline 1",
71+
sub_headline="My Sub Headline 1",
72+
body="My Body 1",
73+
created_at=datetime.now(timezone.utc),
74+
updated_at=datetime.now(timezone.utc),
75+
)
76+
77+
mock_db_session.query(Squeeze).filter(
78+
Squeeze.id == squeeze.id
79+
).first.return_value = squeeze
80+
return squeeze
81+
82+
83+
def test_update_squeeze_success(
84+
client, mock_db_session, exisiting_squeeze, valid_squeeze, mock_get_current_admin
85+
):
86+
"""Test to successfully update a squeeze page"""
87+
88+
# Mock the dependencies
89+
app.dependency_overrides[get_db] = lambda: mock_db_session
90+
app.dependency_overrides[user_service.get_current_super_admin] = (
91+
lambda: mock_get_current_admin
92+
)
93+
94+
response = client.put(
95+
f"api/v1/squeeze/{exisiting_squeeze.id}",
96+
headers={"Authorization": "Bearer token"},
97+
json=valid_squeeze.model_dump(),
98+
)
99+
100+
assert response.status_code == 200
101+
response_data = response.json()
102+
assert response_data["data"]["title"] == valid_squeeze.title
103+
assert response_data["data"]["headline"] == valid_squeeze.headline
104+
105+
106+
def test_update_squeeze_not_found(
107+
client, mock_db_session, valid_squeeze, mock_get_current_admin
108+
):
109+
"""Test updating a non-existent squeeze page"""
110+
111+
non_existent_id = str(uuid7())
112+
mock_db_session.query(Squeeze).filter(
113+
Squeeze.id == non_existent_id
114+
).first.return_value = None
115+
116+
# Mock the dependencies
117+
app.dependency_overrides[get_db] = lambda: mock_db_session
118+
app.dependency_overrides[user_service.get_current_super_admin] = (
119+
lambda: mock_get_current_admin
120+
)
121+
122+
response = client.put(
123+
f"api/v1/squeeze/{non_existent_id}",
124+
headers={"Authorization": "Bearer token"},
125+
json=valid_squeeze.model_dump(),
126+
)
127+
128+
assert response.status_code == 404
129+
130+
131+
def test_update_squeeze_internal_error(
132+
client, mock_db_session, exisiting_squeeze, valid_squeeze, mock_get_current_admin
133+
):
134+
"""Test for internal server error during update"""
135+
136+
# Simulate a database error
137+
mock_db_session.commit.side_effect = Exception("Database error")
138+
139+
# Mock the dependencies
140+
app.dependency_overrides[get_db] = lambda: mock_db_session
141+
app.dependency_overrides[user_service.get_current_super_admin] = (
142+
lambda: mock_get_current_admin
143+
)
144+
145+
response = client.put(
146+
f"api/v1/squeeze/{exisiting_squeeze.id}",
147+
headers={"Authorization": "Bearer token"},
148+
json=valid_squeeze.model_dump(),
149+
)
150+
151+
assert response.status_code == 500

0 commit comments

Comments
 (0)