Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
…python_fastapi_web into feat/implement-status-page
  • Loading branch information
JoshuaOloton committed Aug 24, 2024
2 parents 69bb51d + 7aa8a2b commit c20d01f
Show file tree
Hide file tree
Showing 35 changed files with 1,286 additions and 247 deletions.
51 changes: 51 additions & 0 deletions .github/workflows/regression-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
name: Run Regression Tests

on:
schedule:
- cron: '*/15 * * * *' # Runs every 15 minutes
workflow_dispatch:


jobs:
run-newman-test:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: "20"

- name: Install Newman
run: |
npm install -g newman
- name: Run Newman Tests
run: |
newman run qa_tests/Boilerplate-status-page.postman_collection.json -r json --reporter-json-export=result.json --suppress-exit-code
- name: Copy result.json to server
uses: appleboy/[email protected]
with:
host: ${{ secrets.HOST }}
username: ${{ secrets.USERNAME }}
password: ${{ secrets.PASSWORD }}
source: "result.json"
target: "/home/${{ secrets.USERNAME }}/hng_boilerplate_python_fastapi_web/staging"

- name: Deploy to Server
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.HOST }}
username: ${{ secrets.USERNAME }}
password: ${{ secrets.PASSWORD }}
script: |
cd hng_boilerplate_python_fastapi_web/staging
git add .
git stash
git pull origin staging
python3 update_api_status.py
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ MANIFEST
test_case1.py
api/core/dependencies/mailjet.py
tests/v1/waitlist/waitlist_test.py

result.json
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
Expand Down
2 changes: 2 additions & 0 deletions api/v1/models/billing_plan.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# app/models/billing_plan.py
from sqlalchemy import Column, String, ARRAY, ForeignKey, Numeric, Boolean
from sqlalchemy.orm import relationship
from sqlalchemy import DateTime
from api.v1.models.base_model import BaseTableModel


Expand Down Expand Up @@ -34,3 +35,4 @@ class UserSubscription(BaseTableModel):
user = relationship("User", back_populates="subscriptions")
billing_plan = relationship("BillingPlan", back_populates="user_subscriptions")
organisation = relationship("Organisation", back_populates="user_subscriptions")
billing_cycle = Column(DateTime, nullable=True)
25 changes: 14 additions & 11 deletions api/v1/routes/billing_plan.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,15 @@
from api.v1.services.billing_plan import billing_plan_service
from api.db.database import get_db
from api.v1.services.user import user_service
from api.v1.schemas.plans import CreateSubscriptionPlan
from api.v1.schemas.plans import (
CreateBillingPlanSchema, CreateBillingPlanResponse, GetBillingPlanListResponse
)


bill_plan = APIRouter(prefix="/organisations", tags=["Billing-Plan"])


@bill_plan.get("/{organisation_id}/billing-plans", response_model=success_response)
@bill_plan.get("/{organisation_id}/billing-plans", response_model=GetBillingPlanListResponse)
async def retrieve_all_billing_plans(
organisation_id: str, db: Session = Depends(get_db)
):
Expand All @@ -34,10 +37,10 @@ async def retrieve_all_billing_plans(
)


@bill_plan.post("/billing-plans", response_model=success_response)
@bill_plan.post("/billing-plans", response_model=CreateBillingPlanResponse)
async def create_new_billing_plan(
request: CreateSubscriptionPlan,
current_user: User = Depends(user_service.get_current_super_admin),
request: CreateBillingPlanSchema,
_: User = Depends(user_service.get_current_super_admin),
db: Session = Depends(get_db),
):
"""
Expand All @@ -53,11 +56,11 @@ async def create_new_billing_plan(
)


@bill_plan.patch("/billing-plans/{billing_plan_id}", response_model=success_response)
@bill_plan.patch("/billing-plans/{billing_plan_id}", response_model=CreateBillingPlanResponse)
async def update_a_billing_plan(
billing_plan_id: str,
request: CreateSubscriptionPlan,
current_user: User = Depends(user_service.get_current_super_admin),
request: CreateBillingPlanSchema,
_: User = Depends(user_service.get_current_super_admin),
db: Session = Depends(get_db),
):
"""
Expand All @@ -76,7 +79,7 @@ async def update_a_billing_plan(
@bill_plan.delete("/billing-plans/{billing_plan_id}", response_model=success_response)
async def delete_a_billing_plan(
billing_plan_id: str,
current_user: User = Depends(user_service.get_current_super_admin),
_: User = Depends(user_service.get_current_super_admin),
db: Session = Depends(get_db),
):
"""
Expand All @@ -91,11 +94,11 @@ async def delete_a_billing_plan(
)


@bill_plan.get('/billing-plans/{billing_plan_id}', response_model=success_response)
@bill_plan.get('/billing-plans/{billing_plan_id}', response_model=CreateBillingPlanResponse)
async def retrieve_single_billing_plans(
billing_plan_id: str,
db: Session = Depends(get_db),
current_user: User = Depends(user_service.get_current_user)
_: User = Depends(user_service.get_current_user)
):
"""
Endpoint to get single billing plan by id
Expand Down
52 changes: 50 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, 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 @@ -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,43 @@ async def update_blog_comment(
status_code=200,
data=jsonable_encoder(updated_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)


@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)
20 changes: 15 additions & 5 deletions api/v1/routes/faq.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from fastapi import APIRouter, Depends, status
from fastapi import APIRouter, Depends, status, Query
from fastapi.encoders import jsonable_encoder
from sqlalchemy.orm import Session
from typing import Optional

from api.db.database import get_db
from api.utils.pagination import paginated_response
Expand All @@ -15,15 +16,24 @@


@faq.get("", response_model=success_response, status_code=200)
async def get_all_faqs(db: Session = Depends(get_db),):
"""Endpoint to get all FAQs"""
async def get_all_faqs(
db: Session = Depends(get_db),
keyword: Optional[str] = Query(None, min_length=1)
):
"""Endpoint to get all FAQs or search by keyword in both question and answer"""

query_params = {}
if keyword:
query_params["question"] = keyword
query_params["answer"] = keyword

faqs = faq_service.fetch_all(db=db)
grouped_faqs = faq_service.fetch_all_grouped_by_category(
db=db, **query_params)

return success_response(
status_code=200,
message="FAQs retrieved successfully",
data=jsonable_encoder(faqs),
data=jsonable_encoder(grouped_faqs),
)


Expand Down
Loading

0 comments on commit c20d01f

Please sign in to comment.