Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
44 changes: 39 additions & 5 deletions backend/api/endpoints/command.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,45 +2,79 @@
from fastapi.exceptions import HTTPException
from sqlmodel import Session, select


from backend.api.models.request_model import CommandRequest
from backend.api.models.response_model import CommandListResponse, CommandSingleResponse
from backend.data.data_models import Command
from backend.data.engine import get_db


# Prefix: "/commands"
command_router = APIRouter(tags=["Commands"])




@command_router.get("/", response_model=CommandListResponse)
def get_commands(db: Session = Depends(get_db)):
"""
Gets all the items


@return Returns a list of commands
"""
query = select(Command)
items = db.exec(query).all()
return {"data": items}




@command_router.post("/", response_model=CommandSingleResponse)
def create_command(payload: CommandRequest):
def create_command(payload: CommandRequest, db: Session = Depends(get_db)):
"""
Creates an item with the given payload in the database and returns this payload after pulling it from the database
Creates an item with the given payload in the database and returns this payload after pulling it from the database


@param payload: The data used to create an item
@return returns a json object with field of "data" under which there is the payload now pulled from the database
@return returns a json object with field of "data" under which there is the payload now pulled from the database
"""
# TODO:(Member) Implement this endpoint

try:
new_command = Command(**payload.model_dump())

db.add(new_command)
db.commit()
db.refresh(new_command)

return {"data": new_command}
except Exception as e:
db.rollback()
raise HTTPException(status_code=500, detail="Fail to create command {str(e)}")




@command_router.delete("/{id}", response_model=CommandListResponse)
def delete_command(id: int):
def delete_command(id: int, db: Session = Depends(get_db)):
"""
Deletes the item with the given id if it exists. Otherwise raises a 404 error.


@param id: The id of the item to delete
@return returns the list of commands after deleting the item
"""
# TODO:(Member) Implement this endpoint
query = select(Command)
command = db.exec(query.where(Command.id == id)).first()

if command is None:
raise HTTPException(status_code=404, detail="Item not found")

db.delete(command)
db.commit()

return get_commands(db)



17 changes: 16 additions & 1 deletion backend/api/middlewares/logger_middleware.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
from time import time, strftime
from collections.abc import Callable
from typing import Any
from fastapi import Request, Response
from starlette.middleware.base import BaseHTTPMiddleware

from backend.utils.logging import logger

class LoggerMiddleware(BaseHTTPMiddleware):
async def dispatch(
Expand All @@ -18,5 +20,18 @@ async def dispatch(
@return Response from endpoint
"""
# TODO:(Member) Finish implementing this method
start_time = time()
request_time = strftime('%Y-%m-%d %H:%M:%S')
logger.info(f"Request started: [{request_time}] | {request.method} | {request.url.path} | Params: {request.query_params}")

response = await call_next(request)
return response

raw_byte = b""
async for chunk in response.body_iterator:
raw_byte += chunk

# Log response details and duration
duration = time() - start_time

logger.info(f"Response sent: {raw_byte} {response.status_code} | Duration: {duration:.4f}s")
return Response(content=raw_byte, status_code=response.status_code, headers=dict(response.headers), media_type=response.media_type)
22 changes: 21 additions & 1 deletion backend/data/data_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,23 @@
from pydantic import model_validator
from sqlmodel import Field


from backend.data.base_model import BaseSQLModel
from backend.data.enums import CommandStatus




class MainCommand(BaseSQLModel, table=True):
"""
Main command model.
This table represents all the possible commands that can be issued.


List of commands: https://docs.google.com/spreadsheets/d/1XWXgp3--NHZ4XlxOyBYPS-M_LOU_ai-I6TcvotKhR1s/edit?gid=564815068#gid=564815068
"""


id: int | None = Field(
default=None, primary_key=True
) # NOTE: Must be None for autoincrement
Expand All @@ -25,6 +30,7 @@ class MainCommand(BaseSQLModel, table=True):
data_size: int
total_size: int


@model_validator(mode="after")
def validate_params_format(self):
"""
Expand All @@ -33,7 +39,17 @@ def validate_params_format(self):
The format of the comma seperated values is "data1,data2" so no spaces between data and the commas.
"""
# TODO: (Member) Implement this method
return self
if self.params is None and self.format is None:
return self
elif self.params is None or self.format is None:
raise ValueError("One of params or format is not initialized.")

if len(self.params.split(",")) == len(self.format.split(",")):
return self
else:
raise ValueError("Number of comma separated value of params and format does not match.")




class Command(BaseSQLModel, table=True):
Expand All @@ -42,6 +58,7 @@ class Command(BaseSQLModel, table=True):
This table holds the data related to actual commands sent from the ground station up to the OBC.
"""


id: int | None = Field(
default=None, primary_key=True
) # NOTE: Must be None for autoincrement
Expand All @@ -52,3 +69,6 @@ class Command(BaseSQLModel, table=True):
params: str | None = None
created_on: datetime = datetime.now()
updated_on: datetime = datetime.now()



Loading