-
Notifications
You must be signed in to change notification settings - Fork 134
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #934 from JoshuaOloton/feat/post-user-faq-inquirie…
…s-form feat: post user faq inquiries form
- Loading branch information
Showing
9 changed files
with
305 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
{% extends 'admin-base.html' %} | ||
|
||
{% block title %} | ||
Magic Link | ||
{% endblock %} | ||
|
||
{% block content %} | ||
<div class="container" | ||
style=" | ||
width: 100%; | ||
max-width: 600px; | ||
margin: auto; | ||
padding: 20px; | ||
font-family: Arial, sans-serif; | ||
color: #333; | ||
"> | ||
<div class="header" | ||
style=" | ||
text-align: center; | ||
padding-bottom: 20px; | ||
"> | ||
<h2>Dear {{ full_name }},</h2> | ||
<p>Thank you for your inquiry! We're processing your request, and here's a copy of for your records:</p> | ||
</div> | ||
<div class="content" | ||
style=" | ||
margin-bottom: 20px; | ||
"> | ||
<h3>User Details</h3> | ||
<ul> | ||
<li><span class="highlight" | ||
style=" | ||
font-weight: bold; color: #333; | ||
"> | ||
Full Name:</span> {{ full_name }}</li> | ||
<li> | ||
<span class="highlight" | ||
style=" | ||
font-weight: bold; color: #333; | ||
"> | ||
Email:</span> {{ email }} | ||
</li> | ||
</ul> | ||
<h3>Message</h3> | ||
<p class="message" style="margin-top: 10px;"> | ||
{{ message }} | ||
</p> | ||
</div> | ||
</div> | ||
{% endblock %} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
from sqlalchemy import Column, String, Text | ||
from api.v1.models.base_model import BaseTableModel | ||
|
||
|
||
class FAQInquiries(BaseTableModel): | ||
__tablename__ = "faq_inquiries" | ||
|
||
email = Column(String, nullable=False) | ||
full_name = Column(String, nullable=False) | ||
message = Column(Text, nullable=False) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
from fastapi import APIRouter, status, BackgroundTasks, Depends | ||
from api.core.responses import SUCCESS | ||
from api.db.database import get_db | ||
from api.utils.send_mail import send_faq_inquiry_mail | ||
from api.utils.success_response import success_response | ||
from api.v1.models.user import User | ||
from api.v1.schemas.faq_inquiries import CreateFAQInquiry | ||
from api.v1.services.faq_inquiries import faq_inquiries_service | ||
from api.v1.services.user import user_service | ||
from sqlalchemy.orm import Session | ||
from typing import Annotated | ||
|
||
faq_inquiries = APIRouter(prefix="/faq-inquiries", tags=["FAQ-Inquiries"]) | ||
|
||
# CREATE | ||
@faq_inquiries.post( | ||
"", | ||
response_model=success_response, | ||
status_code=status.HTTP_201_CREATED, | ||
responses={ | ||
201: {"description": "FAQ Inquiry created successfully"}, | ||
422: {"description": "Validation Error"}, | ||
}, | ||
) | ||
async def create_faq_inquiry( | ||
data: CreateFAQInquiry, db: Annotated[Session, Depends(get_db)], | ||
background_tasks: BackgroundTasks, | ||
): | ||
"""Add a new FAQ Inquiry.""" | ||
new_faq_inquiry = faq_inquiries_service.create(db, data) | ||
|
||
# Send email to admin | ||
background_tasks.add_task( | ||
send_faq_inquiry_mail, | ||
context={ | ||
"full_name": new_faq_inquiry.full_name, | ||
"email": new_faq_inquiry.email, | ||
"message": new_faq_inquiry.message, | ||
} | ||
) | ||
|
||
response = success_response( | ||
message=SUCCESS, | ||
data={"id": new_faq_inquiry.id}, | ||
status_code=status.HTTP_201_CREATED, | ||
) | ||
return response | ||
|
||
# READ | ||
@faq_inquiries.get( | ||
"", | ||
response_model=success_response, | ||
status_code=200 | ||
) | ||
async def get_all_faq_inquiries( | ||
db: Annotated[Session, Depends(get_db)], | ||
admin: User = Depends(user_service.get_current_super_admin), | ||
): | ||
"""Fetch all FAQ Inquiries.""" | ||
faq_inquiries = faq_inquiries_service.fetch_all(db) | ||
response = success_response( | ||
message=SUCCESS, | ||
data=faq_inquiries, | ||
status_code=status.HTTP_200_OK, | ||
) | ||
return response |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
from pydantic import BaseModel, EmailStr, Field | ||
|
||
class CreateFAQInquiry(BaseModel): | ||
"""Validate the FAQ Inquiry form data.""" | ||
|
||
full_name: str = Field(..., example="John Doe") | ||
email: EmailStr = Field(..., example="[email protected]") | ||
message: str = Field(..., example="I have a question about the product.") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
from fastapi import Depends | ||
from api.core.base.services import Service | ||
from api.v1.models.faq_inquiries import FAQInquiries | ||
from api.v1.schemas.faq_inquiries import CreateFAQInquiry | ||
from sqlalchemy.orm import Session | ||
from typing import Annotated, Optional, Any | ||
from api.v1.routes.faq_inquiries import get_db | ||
|
||
|
||
class FAQInquiryService(Service): | ||
"""FAQ Inquiry Service.""" | ||
|
||
def __init__(self) -> None: | ||
self.adabtingMapper = { | ||
"full_name": "full_name", | ||
"email": "email", | ||
"message": "message", | ||
} | ||
super().__init__() | ||
|
||
# ------------ CRUD functions ------------ # | ||
# CREATE | ||
def create(self, db: Annotated[Session, Depends(get_db)], data: CreateFAQInquiry): | ||
"""Create a new FAQ Inquiry.""" | ||
faq_inquiry = FAQInquiries( | ||
full_name=getattr(data, self.adabtingMapper["full_name"]), | ||
email=getattr(data, self.adabtingMapper["email"]), | ||
message=getattr(data, self.adabtingMapper["message"]), | ||
) | ||
db.add(faq_inquiry) | ||
db.commit() | ||
db.refresh(faq_inquiry) | ||
return faq_inquiry | ||
|
||
# READ | ||
def fetch_all(self, db: Session, **query_params: Optional[Any]): | ||
"""Fetch all submisions with option to search using query parameters""" | ||
|
||
query = db.query(FAQInquiries) | ||
|
||
# Enable filter by query parameter | ||
if query_params: | ||
for column, value in query_params.items(): | ||
if hasattr(FAQInquiries, column) and value: | ||
query = query.filter(getattr(FAQInquiries, column).ilike(f"%{value}%")) | ||
|
||
return query.all() | ||
|
||
def fetch(self, db: Session, id: str): | ||
"""Fetches a faq_inquiry by id""" | ||
|
||
faq_inquiry = db.query(FAQInquiries).get(id) | ||
return faq_inquiry | ||
|
||
def fetch_by_email(self, db: Session, email: str): | ||
"""Fetches a faq_inquiry by email""" | ||
|
||
faq_inquiry = db.query(FAQInquiries).filter(FAQInquiries.email == email).first() | ||
return faq_inquiry | ||
|
||
def delete(self, db: Session, id: str): | ||
"""Delete a faq_inquiry by id""" | ||
|
||
faq_inquiry = db.query(FAQInquiries).get(id) | ||
db.delete(faq_inquiry) | ||
db.commit() | ||
return faq_inquiry | ||
|
||
def update(self, db: Session, id: str, data: CreateFAQInquiry): | ||
faq_inquiry = db.query(FAQInquiries).get(id) | ||
faq_inquiry.full_name = data.full_name | ||
faq_inquiry.email = data.email | ||
faq_inquiry.message = data.message | ||
db.commit() | ||
db.refresh(faq_inquiry) | ||
return faq_inquiry | ||
|
||
|
||
faq_inquiries_service = FAQInquiryService() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
from datetime import datetime, timezone | ||
from unittest.mock import MagicMock, patch | ||
|
||
import pytest | ||
from fastapi.testclient import TestClient | ||
from sqlalchemy.orm import Session | ||
from uuid_extensions import uuid7 | ||
|
||
from api.db.database import get_db | ||
from api.utils.send_mail import send_faq_inquiry_mail | ||
from api.v1.models.faq_inquiries import FAQInquiries | ||
from main import app | ||
|
||
|
||
|
||
@pytest.fixture | ||
def db_session_mock(): | ||
db_session = MagicMock(spec=Session) | ||
return db_session | ||
|
||
@pytest.fixture | ||
def client(db_session_mock): | ||
app.dependency_overrides[get_db] = lambda: db_session_mock | ||
client = TestClient(app) | ||
yield client | ||
app.dependency_overrides = {} | ||
|
||
|
||
def mock_post_inquiry(): | ||
return FAQInquiries( | ||
id=str(uuid7()), | ||
full_name="John Doe", | ||
email="[email protected]", | ||
message="I have a question about the product.", | ||
) | ||
|
||
|
||
@patch('fastapi.BackgroundTasks.add_task') | ||
@patch("api.v1.services.faq_inquiries.faq_inquiries_service.create") | ||
def test_submit_faq_inquiries(mock_post_inquiry_form, mock_add_task, db_session_mock, client): | ||
"""Tests the POST /api/v1/newsletter-subscription endpoint to ensure successful subscription with valid input.""" | ||
|
||
mock_post_inquiry_form.return_value = mock_post_inquiry() | ||
|
||
db_session_mock.add.return_value = None | ||
db_session_mock.commit.return_value = None | ||
db_session_mock.refresh.return_value = None | ||
|
||
response = client.post('/api/v1/faq-inquiries', json={ | ||
"full_name": "John Doe", | ||
"email": "[email protected]", | ||
"message": "I have a question about the product." | ||
}) | ||
|
||
assert response.status_code == 201 | ||
|
||
mock_add_task.assert_called_once() | ||
mock_add_task.assert_called_with( | ||
send_faq_inquiry_mail, | ||
context={ | ||
"full_name": "John Doe", | ||
"email": "[email protected]", | ||
"message": "I have a question about the product.", | ||
} | ||
) |