Skip to content

Commit 5f83989

Browse files
committed
Change image API
1 parent 93a2663 commit 5f83989

File tree

6 files changed

+124
-9
lines changed

6 files changed

+124
-9
lines changed

backend/controller/plant_controller.py

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
from fastapi import APIRouter, Depends, HTTPException
1+
from fastapi import APIRouter, Depends, HTTPException, File, UploadFile
22
from schemas.plant_schema import PlantSchema
33
from schemas.user_schema import UserSchema
44
from services.plant_service import get_service, PlantService
55
from fastapi import Depends
66
from fastapi.responses import JSONResponse
77
from config.authentication import get_current_user
8+
from pathlib import Path
89

910

1011
create_plant = APIRouter()
@@ -48,4 +49,36 @@ def get_plant_data(
4849
except HTTPException as he:
4950
raise he
5051
except Exception as e:
51-
return JSONResponse(status_code=500, content={"status": "error", "error": f"Unexpected error: {str(e)}"})
52+
JSONResponse(status_code=500, content={"status": "error", "error": f"Unexpected error: {str(e)}"})
53+
54+
55+
# Define allowed file types and max file size (in bytes)
56+
ALLOWED_FILE_TYPES = {"image/jpeg", "image/png"}
57+
MAX_FILE_SIZE = 5 * 1024 * 1024 # 5 MB
58+
59+
@create_plant.put("/api/plant/data/{plant_id}", response_model=PlantSchema)
60+
async def update_plant_image(
61+
plant_id: int,
62+
file: UploadFile = File(...),
63+
service: PlantService = Depends(get_service)
64+
):
65+
# Validate file type
66+
if file.content_type not in ALLOWED_FILE_TYPES:
67+
raise HTTPException(status_code=400, detail="Invalid file type. Only JPEG and PNG are allowed.")
68+
69+
# Validate file size
70+
file_content = await file.read()
71+
if len(file_content) > MAX_FILE_SIZE:
72+
raise HTTPException(status_code=400, detail="File size exceeds the maximum limit of 5 MB.")
73+
74+
# Reset file read position
75+
await file.seek(0)
76+
77+
# Update the plant entry with the new image filename and content
78+
response = service.update_plant_image(plant_id, file.filename, file_content)
79+
80+
if "error" in response:
81+
status_code = 400 if "Not Found" in response["error"] else 500
82+
return JSONResponse(status_code=status_code, content={"status": "error", "error": response["error"]})
83+
84+
return response

backend/dal/plant_dal.py

Lines changed: 78 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@
22
from schemas.plant_schema import PlantSchema
33
import psycopg2
44
from psycopg2 import DatabaseError, IntegrityError
5+
from pathlib import Path
6+
import os
7+
from fastapi.responses import FileResponse
8+
9+
510

611
class PlantDAL:
712
def __init__(self):
@@ -16,9 +21,9 @@ def create_plant(self, plant: PlantSchema):
1621

1722
# Execute the query to insert the plant data
1823
self.cursor.execute("""
19-
INSERT INTO plant (PlantID, PlantName, ScientificName, Threshold)
20-
VALUES (%s, %s, %s, %s) RETURNING PlantID;
21-
""", (plant.PlantID, plant.PlantName, plant.ScientificName, plant.Threshold))
24+
INSERT INTO plant (PlantID, PlantName, ScientificName, Threshold, ImageFileName)
25+
VALUES (%s, %s, %s, %s, %s) RETURNING PlantID;
26+
""", (plant.PlantID, plant.PlantName, plant.ScientificName, plant.Threshold, plant.ImageFilename))
2227

2328
# Commit the transaction
2429
self.conn.commit()
@@ -32,7 +37,8 @@ def create_plant(self, plant: PlantSchema):
3237
"PlantID": plant_id,
3338
"PlantName": plant.PlantName,
3439
"ScientificName": plant.ScientificName,
35-
"Threshhold": plant.Threshhold
40+
"Threshhold": plant.Threshhold,
41+
"ImageFilename": plant.ImageFilename
3642
}
3743

3844
except IntegrityError as e:
@@ -81,7 +87,7 @@ def create_plant(self, plant: PlantSchema):
8187
def get_plants(self):
8288
try:
8389

84-
self.cursor.execute( "SELECT PlantID, PlantName, ScientificName, Threshold FROM plant;")
90+
self.cursor.execute( "SELECT PlantID, PlantName, ScientificName, Threshold FROM plant;") # + ImageFilename maybe?
8591

8692
plants= self.cursor.fetchall()
8793

@@ -98,6 +104,7 @@ def get_plants(self):
98104
"PlantName": plant[1],
99105
"ScientificName": plant[2],
100106
"Threshhold": plant[3]
107+
#"ImageFilename" plant[4]
101108
}
102109
for plant in plants
103110
]
@@ -127,6 +134,72 @@ def get_plants(self):
127134
"error": error_message
128135
}
129136

137+
finally:
138+
# Ensure that the connection is released
139+
release_connection(self.conn)
140+
141+
142+
def update_plant_image(self, plant_id: int, new_image_filename: str, file_content: bytes):
143+
try:
144+
# Query for the current image filename
145+
self.cursor.execute("SELECT ImageFilename FROM plant WHERE PlantID = %s;", (plant_id,))
146+
result = self.cursor.fetchone()
147+
if not result:
148+
return {"status": "error", "error": "Plant not found"}
149+
150+
current_image_filename = result[0]
151+
152+
# Define the image directory
153+
IMAGE_DIR = Path("/path/to/your/image/directory")
154+
155+
# Delete the old image file if it exists
156+
if current_image_filename:
157+
old_image_path = IMAGE_DIR / current_image_filename
158+
if old_image_path.exists():
159+
os.remove(old_image_path)
160+
161+
# Save the new image file
162+
new_image_path = IMAGE_DIR / new_image_filename
163+
with open(new_image_path, "wb") as buffer:
164+
buffer.write(file_content)
165+
166+
# Update the image filename in the database
167+
self.cursor.execute("""
168+
UPDATE plant
169+
SET ImageFilename = %s
170+
WHERE PlantID = %s;
171+
""", (new_image_filename, plant_id))
172+
173+
# Commit the transaction
174+
self.conn.commit()
175+
176+
# Return the updated image
177+
return FileResponse(
178+
path=str(new_image_path),
179+
filename=new_image_filename
180+
)
181+
182+
183+
except (psycopg2.Error, DatabaseError) as db_error:
184+
# Handle database errors
185+
self.conn.rollback() # Rollback transaction on error
186+
error_message = f"Database error: {db_error}"
187+
print(f"Database error: {db_error}")
188+
return {
189+
"status": "error",
190+
"error": error_message
191+
}
192+
193+
except Exception as e:
194+
# Catch any other unexpected errors
195+
self.conn.rollback() # Rollback transaction on error
196+
error_message = f"Unexpected error: {e}"
197+
print(f"Unexpected error: {e}")
198+
return {
199+
"status": "error",
200+
"error": error_message
201+
}
202+
130203
finally:
131204
# Ensure that the connection is released
132205
release_connection(self.conn)

backend/models/models.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ class Plant(Base):
77
PlantName = Column(String(50), nullable=False)
88
ScientificName = Column(String(50), nullable=False)
99
Threshhold = Column(Float, nullable=False)
10+
ImageFilename = Column(String(255), nullable=True) # New column for image filename
1011

1112
class Sensor(Base):
1213
__tablename__ = "sensors"

backend/repository/plant_repository.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,7 @@ def add_plant(self, plant: PlantSchema):
99
return self.dal.create_plant(plant)
1010

1111
def get_plants(self):
12-
return self.dal.get_plants()
12+
return self.dal.get_plants()
13+
14+
def update_plant_image(self, plant_id: int, new_image_filename: str, file_content: bytes):
15+
return self.dal.update_plant_image(plant_id, new_image_filename)

backend/schemas/plant_schema.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
from pydantic import BaseModel
2+
from typing import Optional
23

34
class PlantSchema(BaseModel):
45
PlantID: int
56
PlantName: str
67
ScientificName: str
7-
Threshold: float
8+
Threshold: float
9+
ImageFilename: Optional[str] = None # Optional field for image filename

backend/services/plant_service.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ def create_plant(self, plant: PlantSchema):
1313
def get_plants(self):
1414
return self.repository.get_plants()
1515

16+
def update_plant_image(self, plant_id: int, new_image_filename: str, file_content: bytes):
17+
# Pass the file content to the repository
18+
return self.repository.update_plant_image(plant_id, new_image_filename, file_content)
1619

1720
def get_service():
1821
dal = PlantDAL()

0 commit comments

Comments
 (0)