Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
89ef25d
added Get api
Itsc2y Nov 6, 2024
facc35c
Adding Delete APIs
Nov 6, 2024
34bc075
Added Put API
Xingjian-Li-117 Nov 6, 2024
9058a84
added post
joycelalalayaa Nov 7, 2024
b71851c
Connected to MongoDB database and updated APIs.
Xingjian-Li-117 Nov 20, 2024
f5ab342
Create pylint action
joycelalalayaa Nov 23, 2024
847cc7b
Added a simpler way to run the server
joycelalalayaa Nov 23, 2024
65651e2
Create pylint action
joycelalalayaa Nov 23, 2024
fcaa962
Improved import order
joycelalalayaa Nov 23, 2024
f73e81b
Added runServer.sh + got rid of some unused code
joycelalalayaa Nov 23, 2024
5838c24
made some updated to router.py
joycelalalayaa Nov 24, 2024
f3730bf
made some updated to logic.py
joycelalalayaa Nov 24, 2024
586b386
Updating schema and database
Nov 24, 2024
345b243
Updating schema and database
Nov 24, 2024
c53fe78
Merge pull request #6 from Itsc2y/testBranch
tianjiewang2022 Nov 24, 2024
3b1a99c
Updating python version on pylint
Nov 24, 2024
d66c576
Updating python version on pylint
Nov 24, 2024
3f03d56
Merge pull request #7 from Itsc2y/testBranch
tianjiewang2022 Nov 24, 2024
54ab6dc
fix pylint errors
Itsc2y Nov 24, 2024
a9e4350
edit pylint
Itsc2y Nov 24, 2024
d89a10c
Updated router.py
Xingjian-Li-117 Nov 24, 2024
efcec61
edit pylint
Itsc2y Nov 24, 2024
fb4e2dc
edit pylint and requirement
Itsc2y Nov 24, 2024
db3c3e2
Updated model.py
Xingjian-Li-117 Nov 24, 2024
1bdac78
Second update on model.py
Xingjian-Li-117 Nov 24, 2024
145447e
made some updated to logic.py
joycelalalayaa Nov 24, 2024
e6b1ba0
made some updated to logic.py
joycelalalayaa Nov 24, 2024
b6342b9
add docker files
Itsc2y Nov 27, 2024
1a8a94b
Fix Docker login issue
Itsc2y Nov 27, 2024
61153bd
Use GitHub secrets for MongoDB configuration
Itsc2y Nov 27, 2024
0d13a3b
fix
Itsc2y Nov 27, 2024
cdfbd2c
fix
Itsc2y Nov 27, 2024
c2ee3bf
fix
Itsc2y Nov 27, 2024
f234732
fix
Itsc2y Nov 27, 2024
87ed2a9
fix
Itsc2y Nov 27, 2024
f678e17
a
Itsc2y Nov 27, 2024
526a7f1
a
Itsc2y Nov 27, 2024
bd49f87
fix
Itsc2y Nov 27, 2024
833f41e
fix
Itsc2y Nov 27, 2024
d0525b6
fix
Itsc2y Nov 27, 2024
740f2fb
fix
Itsc2y Nov 27, 2024
9db3d09
Merge pull request #9 from Itsc2y/docker_build
Itsc2y Nov 27, 2024
23c9f5c
Added tests for update_client method. Updated config.py to make sure …
Xingjian-Li-117 Dec 2, 2024
6056f16
Merge pull request #10 from Itsc2y/xingjianli
joycelalalayaa Dec 2, 2024
e6b486e
Merge branch 'main' into NewBranchToTestCI
joycelalalayaa Dec 2, 2024
96476b4
edited pylint.yml
joycelalalayaa Dec 2, 2024
8fa1f4a
just testing
joycelalalayaa Dec 3, 2024
73ae157
just testing
joycelalalayaa Dec 3, 2024
a9f2d61
just testing
joycelalalayaa Dec 3, 2024
d2c8522
just testing
joycelalalayaa Dec 3, 2024
bb7a549
just testing
joycelalalayaa Dec 3, 2024
f1bfc5a
just testing
joycelalalayaa Dec 3, 2024
e8f8fda
just testing
joycelalalayaa Dec 3, 2024
d83fe4f
just testing
joycelalalayaa Dec 3, 2024
a2cc3ba
just testing
joycelalalayaa Dec 3, 2024
21fe0c9
just testing
joycelalalayaa Dec 3, 2024
ec61791
just testing
joycelalalayaa Dec 3, 2024
cf5007e
just testing
joycelalalayaa Dec 3, 2024
99be894
just testing
joycelalalayaa Dec 3, 2024
5e97f62
just testing
joycelalalayaa Dec 3, 2024
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
33 changes: 33 additions & 0 deletions .github/workflows/docker-build-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
name: Docker CI Pipeline

on:
push:
branches:
- main
pull_request:
branches:
- main

jobs:
build-and-test:
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Docker
uses: docker/setup-buildx-action@v2

- name: Build Docker Image
run: |
docker build -t fastapi-app .

- name: Run Docker Container
run: |
docker run -d --name fastapi-container -p 8000:8000 fastapi-app

- name: Cleanup
run: |
docker stop fastapi-container
docker rm fastapi-container
45 changes: 45 additions & 0 deletions .github/workflows/docker.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
name: Docker CI Pipeline

on:
push:
branches:
- main
pull_request:
branches:
- main

jobs:
build-and-test:
runs-on: ubuntu-latest

steps:
# Step 1: Check out the code
- name: Checkout code
uses: actions/checkout@v4

# Step 2: Log in to DockerHub (Optional, if pushing the image)
- name: Log in to DockerHub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}

# Step 3: Set up Docker
- name: Set up Docker
uses: docker/setup-buildx-action@v2

# Step 4: Build Docker image
- name: Build Docker Image
run: |
docker build -t fastapi-app .

# Step 5: Run Docker Container with GitHub Secrets
- name: Run Docker Container
run: |
docker run -d -p 8000:8000 -e MONGODB_URI='${{ secrets.MONGODB_URI }}' -e MONGODB_NAME='${{ secrets.MONGODB_NAME }}' fastapi-app:latest

# Step 6: Test API Endpoints
- name: Test API Endpoints
run: |
sleep 5 # Allow time for the container to start
curl -f http://localhost:8000/docs
41 changes: 41 additions & 0 deletions .github/workflows/pylint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
name: Pylint Check

on:
push:
branches:
- NewBranchToTestCI # Trigger workflow on push to this branch
pull_request:
branches:
- NewBranchToTestCI # Trigger workflow on pull requests to this branch

jobs:
lint:
runs-on: ubuntu-latest

steps:
# Step 1: Check out the code
- name: Checkout code
uses: actions/checkout@v3

# Step 2: Set up Python
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: "3.10" # Replace with your Python version (e.g., '3.10')

# Step 2.5: Install system dependencies
- name: Install system dependencies
run: |
sudo apt-get update

# Step 3: Install dependencies
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install pylint
pip install setuptools
pip install -r requirements.txt # Adjust the path if your requirements.txt is elsewhere

# Step 4: Run pylint
- name: Run Pylint
run: pylint ./app; # Replace with the name of your module, file, or directory
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
.venv
venv/
.idea
__pycache__
.DS_Store
.env
30 changes: 30 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Use an official Python runtime as a parent image
FROM python:3.10-slim

# Set environment variables
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1

# Set the working directory in the container
WORKDIR /app

# Install system dependencies required for psutil and other packages
RUN apt-get update && apt-get install -y --no-install-recommends \
gcc \
python3-dev \
libffi-dev \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*

# Install dependencies
COPY requirements.txt /app/requirements.txt
RUN pip install --no-cache-dir --upgrade pip && pip install -r requirements.txt

# Copy the FastAPI app into the container
COPY . /app

# Expose port 8000 for FastAPI
EXPOSE 8000

# Command to run the FastAPI server
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
2 changes: 2 additions & 0 deletions app/.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
MONGODB_URI=mongodb+srv://team:IOi4XgpRxWVkKLv2@cluster0.mcjdj.mongodb.net/?retryWrites=true&w=majority&appName=Cluster0
MONGODB_NAME=Cluster0
166 changes: 157 additions & 9 deletions app/clients/router.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,163 @@
from fastapi import APIRouter
from fastapi.responses import HTMLResponse
"""
This module handles client-related API routes for the application.
"""

from app.clients.service.logic import interpret_and_calculate
from app.clients.schema import PredictionInput
from datetime import datetime, date
from typing import List

from bson import ObjectId
from fastapi import APIRouter, HTTPException

from app.clients.schema import Client, ClientUpdate
from app.database import clients_collection

router = APIRouter(prefix="/clients", tags=["clients"])

@router.post("/predictions")
async def predict(data: PredictionInput):
print("HERE")
print(data.model_dump())
return interpret_and_calculate(data.model_dump())
mock_clients_db = {
1: Client(
id="1",
first_name="Amy",
last_name="Doe",
email="amy.doe@example.com",
date_of_birth="1995-04-23",
address="123 Main St, Springfield",
phone="123-456-7890"
),
2: Client(
id="2",
first_name="Bob",
last_name="Smith",
email="bob.smith@example.com",
date_of_birth="1999-08-17",
address="456 Elm St, Springfield",
phone="098-765-4321"
),
}

def generate_new_id():
"""
Generate a new unique ID for a client.
"""
return max(mock_clients_db.keys(), default=0) + 1


@router.post("/create", response_model=Client, summary="Create a new client")
async def create_client(client_data: Client):
"""
Create a new client in the database.

Args:
client_data (Client): The client data to create.

Returns:
Client: The created client object.
"""
client_dict = client_data.dict(exclude={"id"})
for key, value in client_dict.items():
if isinstance(value, date):
client_dict[key] = datetime.combine(value, datetime.min.time())
result = await clients_collection.insert_one(client_dict)
client_dict["_id"] = result.inserted_id
return Client(id=str(client_dict["_id"]), **client_dict)

@router.get("/clients/{client_id}", response_model=Client, summary="Retrieve client by ID")
async def get_client_by_id(client_id: str):
"""
Retrieve a client by their ID.

Args:
client_id (str): The ID of the client to retrieve.

Returns:
Client: The retrieved client object.
"""
client = await clients_collection.find_one({"_id": ObjectId(client_id)})
if client is None:
raise HTTPException(status_code=404, detail="Client not found")
# Convert ObjectId to string and return a formatted client object
client["id"] = str(client["_id"])
del client["_id"]
return client


@router.get("/clients", response_model=List[Client], summary="Retrieve all clients")
async def get_all_clients():
"""
Retrieve all clients in the database.

Returns:
List[Client]: A list of all clients.
"""
clients_cursor = await clients_collection.find().to_list(length=100)
# Convert _id to id and return the list
for client in clients_cursor:
client["id"] = str(client["_id"])
del client["_id"]

return clients_cursor


@router.delete("/clients/{client_id}", response_model=None, summary="Delete client by ID")
async def delete_client_by_id(client_id: str):
"""
Delete a client by their ID.

Args:
client_id (str): The ID of the client to delete.

Returns:
dict: A message indicating successful deletion.
"""
if not ObjectId.is_valid(client_id):
raise HTTPException(status_code=400, detail="Invalid ObjectId format")

client = await clients_collection.find_one({"_id": ObjectId(client_id)})
if client is None:
raise HTTPException(status_code=404, detail="Client not found")

delete_result = await clients_collection.delete_one({"_id": ObjectId(client_id)})
if delete_result.deleted_count == 0:
raise HTTPException(status_code=404, detail="Client not found")

return {"message": f"Client with ID {client_id} deleted successfully."}
@router.delete("/clients", response_model=None, summary="Delete all clients")
async def delete_all_clients():
"""
Delete all clients in the database.

Returns:
dict: A message indicating successful deletion of all clients.
"""
await clients_collection.delete_many({})
return {"message": "All clients deleted successfully."}


@router.put("/clients/{client_id}", response_model=Client, summary="Update client by ID")
async def update_client(client_id: str, client_data: ClientUpdate):
"""
Update a client's information by their ID.

Args:
client_id (str): The ID of the client to update.
client_data (ClientUpdate): The updated client data.

Returns:
Client: The updated client object.
"""
client = await clients_collection.find_one({"_id": ObjectId(client_id)})
if client is None:
raise HTTPException(status_code=404, detail="Client not found")

# Convert datetime.date to datetime.datetime for fields that are datetime.date
updated_fields = client_data.dict(exclude_unset=True)
for field, value in updated_fields.items():
if isinstance(value, date):
updated_fields[field] = datetime.combine(value, datetime.min.time())

await clients_collection.update_one({"_id": ObjectId(client_id)}, {"$set": updated_fields})

updated_client = await clients_collection.find_one({"_id": ObjectId(client_id)})
updated_client["id"] = str(updated_client["_id"])
del updated_client["_id"]

return updated_client
39 changes: 39 additions & 0 deletions app/clients/schema.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,18 @@
"""
Schemas for client and prediction data models.
Defines Pydantic models for validation and data manipulation.
"""

from datetime import date
from typing import Optional
from pydantic import BaseModel


class PredictionInput(BaseModel):
"""
Schema for prediction input parameters.
Used for validating data submitted for predictions.
"""
age: int
gender: str
work_experience: int
Expand All @@ -25,3 +37,30 @@ class PredictionInput(BaseModel):
substance_use: str
time_unemployed: int
need_mental_health_support_bool: str


class Client(BaseModel):
"""
Schema for client data.
Represents information stored about a client in the database.
"""
id: str
first_name: str
last_name: str
email: str
date_of_birth: date
address: Optional[str] = None
phone: Optional[str] = None


class ClientUpdate(BaseModel):
"""
Schema for client update data.
Used for partial updates to client information.
"""
first_name: Optional[str] = None
last_name: Optional[str] = None
email: Optional[str] = None
date_of_birth: Optional[date] = None
address: Optional[str] = None
phone: Optional[str] = None
Loading