-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'main' into embedded-code
- Loading branch information
Showing
58 changed files
with
24,032 additions
and
15,199 deletions.
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,28 @@ | ||
--- | ||
name: Task - AAA Principle | ||
about: A task template for actionable items using the AAA principle | ||
title: '[Task] - [short task title here]' | ||
labels: task | ||
assignees: '' | ||
|
||
--- | ||
|
||
## **User Story Link:** | ||
User Story: #123 (replace with the User Story issue number) | ||
|
||
## **Task Description:** | ||
[Provide a brief description of the task to be completed.] | ||
|
||
--- | ||
|
||
## **Acceptance Criteria:** | ||
- [ ] **Arrange**: [Define the initial input or setup required for the task.] | ||
- [ ] **Act**: [Define the actions to be taken to complete the task.] | ||
- [ ] **Assert**: [Define the expected outcomes or results after the task is completed.] | ||
|
||
--- | ||
|
||
## **Priority:** [Low/Medium/High] | ||
## **Story Points / Estimate:** [Effort estimate in points or hours] | ||
## **Dependencies:** [List any dependencies or tasks that need to be completed first] | ||
## **Notes / Additional Details:** [Context or extra details, if any] |
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,18 @@ | ||
# Base image | ||
FROM python:3.9-slim | ||
|
||
# Set working directory inside the container | ||
WORKDIR /app | ||
|
||
# Copy the entire backend folder into the container | ||
# Adjusting the path to copy from /backend folder | ||
COPY . /app | ||
|
||
# Install dependencies | ||
RUN pip install --no-cache-dir -r requirements.txt | ||
|
||
# Expose the port your app runs on | ||
EXPOSE 8000 | ||
|
||
# Command to run the application | ||
CMD ["python", "main.py"] |
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 |
---|---|---|
@@ -1 +1,5 @@ | ||
Test feature to close ticket automatically using Closes #18. Hello | ||
<<<<<<< HEAD | ||
Test feature to close ticket automatically using Closes #18. Hello | ||
======= | ||
Test feature to close ticket automatically using Closes #18. Hello | ||
>>>>>>> fe68087a11103b291e8a14f454bdff774de1db60 |
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,14 @@ | ||
from psycopg2 import pool | ||
from sqlalchemy import create_engine | ||
from sqlalchemy.ext.declarative import declarative_base | ||
|
||
DATABASE_URL = "postgresql://neondb_owner:npg_SbW8PXa4dpzK@ep-summer-poetry-a84hp8dp-pooler.eastus2.azure.neon.tech/neondb?sslmode=require" | ||
connection_pool = pool.SimpleConnectionPool(1, 10, DATABASE_URL) | ||
engine = create_engine(DATABASE_URL) | ||
Base = declarative_base() | ||
|
||
def get_connection(): | ||
return connection_pool.getconn() | ||
|
||
def release_connection(conn): | ||
connection_pool.putconn(conn) |
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,48 @@ | ||
from fastapi import APIRouter, Depends, HTTPException | ||
from schemas.plant_schema import PlantSchema | ||
from schemas.user_schema import UserSchema | ||
from services.plant_service import get_service, PlantService | ||
from fastapi import Depends | ||
from fastapi.responses import JSONResponse | ||
from fastapi.security import HTTPBasic, HTTPBasicCredentials | ||
from services.user_service import get_user_service, UserService | ||
|
||
|
||
create_plant = APIRouter() | ||
|
||
security = HTTPBasic() | ||
|
||
|
||
def verify_credentials(credentials: HTTPBasicCredentials = Depends(security), user_service: UserService = Depends(get_user_service)): | ||
username = credentials.username | ||
password = credentials.password | ||
user_schema = UserSchema(username=username, password=password) | ||
print(user_service.verify_user(user_schema)) | ||
if user_service.verify_user(user_schema) == 0: | ||
raise HTTPException( | ||
status_code= 401, | ||
detail="Invalid credentials", | ||
headers={"WWW-Authenticate": "Basic"}, | ||
) | ||
return username | ||
|
||
|
||
@create_plant.post("/api/plant/data", response_model=PlantSchema) | ||
def create_plant_entry(plant: PlantSchema, service: PlantService = Depends(get_service)): | ||
try: | ||
# Call the service layer to create the plant | ||
response = service.create_plant(plant) | ||
|
||
# Check if the response contains an error (we assume error in the response means failure) | ||
if "error" in response: | ||
# If error is present, return the error response with an appropriate status code (400 or 500) | ||
status_code = 400 if "Duplicate" in response["error"] else 500 | ||
return JSONResponse(status_code=status_code, content={"status": "error", "error": response["error"]}) | ||
|
||
# If the response is successful, return the response with a 201 status code | ||
return JSONResponse(status_code=201, content=response) | ||
|
||
except Exception as e: | ||
# If an unexpected error occurs during processing, return a 500 status code | ||
return JSONResponse(status_code=500, content={"status": "error", "error": f"Unexpected error: {str(e)}"}) | ||
|
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 config.database import get_connection, release_connection | ||
from schemas.plant_schema import PlantSchema | ||
import psycopg2 | ||
from psycopg2 import DatabaseError, IntegrityError | ||
|
||
class PlantDAL: | ||
def __init__(self): | ||
self.conn = get_connection() | ||
self.cursor = self.conn.cursor() | ||
|
||
def create_plant(self, plant: PlantSchema): | ||
try: | ||
# Validate input data (optional, based on your requirements) | ||
if not plant.PlantName or not plant.ScientificName or not isinstance(plant.Threshhold, (int, float)): | ||
raise ValueError("Invalid input data") | ||
|
||
# Execute the query to insert the plant data | ||
self.cursor.execute(""" | ||
INSERT INTO plant (PlantID, PlantName, ScientificName, Threshhold) | ||
VALUES (%s, %s, %s, %s) RETURNING PlantID; | ||
""", (plant.PlantID, plant.PlantName, plant.ScientificName, plant.Threshhold)) | ||
|
||
# Commit the transaction | ||
self.conn.commit() | ||
|
||
# Get the returned PlantID | ||
plant_id = self.cursor.fetchone()[0] | ||
|
||
# Return the response in JSON format | ||
return { | ||
"status": "success", | ||
"PlantID": plant_id, | ||
"PlantName": plant.PlantName, | ||
"ScientificName": plant.ScientificName, | ||
"Threshhold": plant.Threshhold | ||
} | ||
|
||
except IntegrityError as e: | ||
# Handle duplicate key error (unique constraint violation) | ||
self.conn.rollback() # Rollback transaction on error | ||
error_message = f"Duplicate entry for PlantID: {plant.PlantID}. A plant with this ID already exists." | ||
print(f"IntegrityError: {e}") | ||
return { | ||
"status": "error", | ||
"error": error_message | ||
} | ||
|
||
except (psycopg2.Error, DatabaseError) as db_error: | ||
# Handle other database errors | ||
self.conn.rollback() # Rollback transaction on error | ||
error_message = f"Database error: {db_error}" | ||
print(f"Database error: {db_error}") | ||
return { | ||
"status": "error", | ||
"error": error_message | ||
} | ||
|
||
except ValueError as val_error: | ||
# Handle input validation errors | ||
error_message = f"Invalid input: {val_error}" | ||
print(f"Input error: {val_error}") | ||
return { | ||
"status": "error", | ||
"error": error_message | ||
} | ||
|
||
except Exception as e: | ||
# Catch any other unexpected errors | ||
self.conn.rollback() # Rollback transaction on error | ||
error_message = f"Unexpected error: {e}" | ||
print(f"Unexpected error: {e}") | ||
return { | ||
"status": "error", | ||
"error": error_message | ||
} | ||
|
||
finally: | ||
# Ensure that the connection is released | ||
release_connection(self.conn) |
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,41 @@ | ||
from config.database import get_connection, release_connection | ||
from schemas.user_schema import UserSchema | ||
import psycopg2 | ||
from psycopg2 import DatabaseError | ||
|
||
class UserDAL: | ||
def __init__(self): | ||
self.conn = get_connection() | ||
self.cursor = self.conn.cursor() | ||
|
||
def verify_user(self, user: UserSchema): | ||
try: | ||
if not user.username or not user.password: | ||
raise ValueError("Username and password must not be empty.") | ||
|
||
self.cursor.execute(""" | ||
SELECT EXISTS ( | ||
SELECT 1 FROM users WHERE username = %s AND password = %s | ||
); | ||
""", (user.username, user.password)) | ||
|
||
return self.cursor.fetchone()[0] # Returns True or False | ||
|
||
except (psycopg2.Error, DatabaseError) as db_error: | ||
self.conn.rollback() | ||
print(f"Database error: {db_error}") | ||
return {"status": "error", "error": str(db_error)} | ||
|
||
except ValueError as val_error: | ||
print(f"Input error: {val_error}") | ||
return {"status": "error", "error": str(val_error)} | ||
|
||
except Exception as e: | ||
self.conn.rollback() | ||
print(f"Unexpected error: {e}") | ||
return {"status": "error", "error": str(e)} | ||
|
||
def __del__(self): | ||
""" Ensure the connection is closed when the object is destroyed. """ | ||
if self.conn: | ||
release_connection(self.conn) |
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,26 @@ | ||
version: '3.8' | ||
|
||
services: | ||
api: | ||
build: ../ | ||
container_name: sproutly-api | ||
networks: | ||
- sproutly-network | ||
expose: | ||
- "8000" | ||
|
||
nginx: | ||
image: nginx:latest | ||
container_name: nginx | ||
ports: | ||
- "80:80" | ||
volumes: | ||
- ./nginx.conf:/etc/nginx/conf.d/default.conf | ||
networks: | ||
- sproutly-network | ||
depends_on: | ||
- api | ||
|
||
networks: | ||
sproutly-network: | ||
driver: bridge |
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,12 @@ | ||
server { | ||
listen 80; | ||
server_name sproutly.com; | ||
|
||
location /api/plant/data { | ||
proxy_pass http://sproutly-api:8000; | ||
proxy_set_header Host $host; | ||
proxy_set_header X-Real-IP $remote_addr; | ||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; | ||
proxy_set_header X-Forwarded-Proto $scheme; | ||
} | ||
} |
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,24 @@ | ||
server { | ||
listen 80; | ||
server_name sproutly.com; | ||
|
||
location / { | ||
return 301 https://$host$request_uri; | ||
} | ||
} | ||
|
||
server { | ||
listen 443 ssl; | ||
server_name sproutly.com; | ||
|
||
ssl_certificate /etc/nginx/ssl/sproutly.crt; | ||
ssl_certificate_key /etc/nginx/ssl/sproutly.key; | ||
|
||
location /api/plant/data { | ||
proxy_pass http://sproutly-api:8000; | ||
proxy_set_header Host $host; | ||
proxy_set_header X-Real-IP $remote_addr; | ||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; | ||
proxy_set_header X-Forwarded-Proto $scheme; | ||
} | ||
} |
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,76 @@ | ||
#!/bin/bash | ||
|
||
|
||
print_message() { | ||
echo -e "\033[1;34m-------------------------------------\033[0m" | ||
echo -e "\033[1;36m$1\033[0m" | ||
echo -e "\033[1;34m-------------------------------------\033[0m" | ||
} | ||
|
||
|
||
print_welcome() { | ||
echo -e "\033[1;32m" | ||
echo "**********************************************" | ||
echo " WELCOME TO THE SPROUTLY SETUP! " | ||
echo "**********************************************" | ||
echo -e "\033[1;33m Let's get your environment set up for success! \033[0m" | ||
echo -e "\033[1;32m" | ||
echo "**********************************************" | ||
echo -e "\033[0m" | ||
} | ||
|
||
# Step 1: Print the welcome message | ||
print_welcome | ||
|
||
# Step 2: Navigate to the backend folder | ||
print_message "Navigating to the backend folder..." | ||
cd "$(dirname "$0")" || exit 1 | ||
|
||
# Step 3: Ensure Docker is installed | ||
print_message "Checking if Docker is installed..." | ||
if command -v docker &> /dev/null; then | ||
echo -e "\033[1;32mDocker is already installed! Let's keep moving.\033[0m" | ||
else | ||
print_message "Docker is not installed. Please install Docker and try again." | ||
exit 1 | ||
fi | ||
|
||
# Step 4: Ensure Docker Compose is installed | ||
print_message "Checking if Docker Compose is installed..." | ||
if command -v docker-compose &> /dev/null; then | ||
echo -e "\033[1;32mDocker Compose is good to go!\033[0m" | ||
else | ||
print_message "Docker Compose is not installed. Please install Docker Compose and try again." | ||
exit 1 | ||
fi | ||
|
||
# Step 5: Navigate to the docker directory where docker-compose.yml is located | ||
print_message "Setting up the Docker environment..." | ||
DOCKER_DIR="./docker" | ||
|
||
# Step 6: Build and start the Docker containers | ||
print_message "Starting Docker containers with Docker Compose..." | ||
docker-compose -f "$DOCKER_DIR/docker-compose.yml" down | ||
docker-compose -f "$DOCKER_DIR/docker-compose.yml" up -d --build | ||
|
||
# Step 7: Verify containers are running | ||
print_message "Checking if the containers are up and running..." | ||
docker ps | ||
|
||
# Step 8: Add sproutly.com to /etc/hosts for local testing | ||
print_message "Updating your /etc/hosts for local testing..." | ||
if ! grep -q "sproutly.com" /etc/hosts; then | ||
echo "127.0.0.1 sproutly.com" | sudo tee -a /etc/hosts | ||
echo -e "\033[1;32mAdded sproutly.com to /etc/hosts. Now you can test locally!\033[0m" | ||
else | ||
echo -e "\033[1;33msproutly.com is already in /etc/hosts.\033[0m" | ||
fi | ||
|
||
# Step 9: Show Docker containers status at the end | ||
print_message "🎉 Setup Complete! 🎉" | ||
echo -e "\033[1;32mThe following Docker containers are now running:\033[0m" | ||
docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}" | ||
|
||
# Final completion message with a bit more flair | ||
echo -e "\033[1;34mThank you for setting up Sproutly with us! 🌱 Your environment is now ready.\033[0m" | ||
echo -e "\033[1;32mYou can start testing at: http://sproutly.com/api/plant/data\033[0m" |
Oops, something went wrong.