diff --git a/gs/backend/api/v1/mcc/endpoints/aro_requests.py b/gs/backend/api/v1/mcc/endpoints/aro_requests.py index 77b8a622c..998f1f85f 100644 --- a/gs/backend/api/v1/mcc/endpoints/aro_requests.py +++ b/gs/backend/api/v1/mcc/endpoints/aro_requests.py @@ -1,3 +1,25 @@ -from fastapi import APIRouter +from fastapi import APIRouter, Query + +from gs.backend.api.v1.mcc.models.responses import ARORequestsResponse +from gs.backend.data.data_wrappers.aro_wrapper.aro_request_wrapper import get_all_requests +from gs.backend.data.enums.aro_requests import ARORequestStatus aro_requests_router = APIRouter(tags=["MCC", "ARO Requests"]) + + +@aro_requests_router.get("/", response_model=ARORequestsResponse) +async def get_aro_requests( + count: int = Query(default=100), + offset: int = Query(default=0), + filters: list[ARORequestStatus] = Query(default=[]), +) -> ARORequestsResponse: + """ + Gets all ARO requests with optional filtering and pagination + + :param count: Number of most recent requests to return. If ≤ 0, returns all data + :param offset: Starting point for paging + :param filters: List of request statuses to filter by. If empty, no filtering is applied + :return: ARO requests matching the criteria + """ + requests = get_all_requests(count, offset, filters) + return ARORequestsResponse(data=requests) diff --git a/gs/backend/api/v1/mcc/models/responses.py b/gs/backend/api/v1/mcc/models/responses.py index c54a95395..35196ee78 100644 --- a/gs/backend/api/v1/mcc/models/responses.py +++ b/gs/backend/api/v1/mcc/models/responses.py @@ -1,6 +1,7 @@ from pydantic import BaseModel from gs.backend.data.tables.main_tables import MainCommand +from gs.backend.data.tables.transactional_tables import ARORequest class MainCommandsResponse(BaseModel): @@ -9,3 +10,11 @@ class MainCommandsResponse(BaseModel): """ data: list[MainCommand] + + +class ARORequestsResponse(BaseModel): + """ + The ARO requests response model. + """ + + data: list[ARORequest] diff --git a/gs/backend/data/data_wrappers/aro_wrapper/aro_request_wrapper.py b/gs/backend/data/data_wrappers/aro_wrapper/aro_request_wrapper.py index 113a9e21f..9613f66ba 100644 --- a/gs/backend/data/data_wrappers/aro_wrapper/aro_request_wrapper.py +++ b/gs/backend/data/data_wrappers/aro_wrapper/aro_request_wrapper.py @@ -2,6 +2,7 @@ from decimal import Decimal from uuid import UUID +from sqlalchemy import desc from sqlmodel import select from gs.backend.data.database.engine import get_db_session @@ -9,12 +10,32 @@ from gs.backend.data.tables.transactional_tables import ARORequest -def get_all_requests() -> list[ARORequest]: +def get_all_requests( + count: int = 100, offset: int = 0, filters: list[ARORequestStatus] | None = None +) -> list[ARORequest]: """ Get all the requests from aro + + :param count: Number of most recent requests to return. If ≤ 0, returns all data + :param offset: Starting point for paging + :param filters: List of request statuses to filter by. If empty, no filtering is applied """ + + if filters is None: + filters = [] + with get_db_session() as session: - requests = list(session.exec(select(ARORequest)).all()) + query = select(ARORequest).order_by(desc(ARORequest.created_on)) # type: ignore + + if filters: + query = query.where(ARORequest.status.in_(filters)) # type: ignore + if offset > 0: + query = query.offset(offset) + if count > 0: + query = query.limit(count) + + requests = list(session.exec(query).all()) + return requests @@ -34,8 +55,9 @@ def add_request( :param long: the longitude represented as a decimal of max 3 decimal places :param lat: the latitude represented as a decimal of max 3 decimal places :param created_on: datetime object representing the date this request was made. defaults to now + :param request_sent_obc: datetime object representing when the request was sent to OBC :param taken_date: datetime object representing the date that this picture was taken on - :param taken_date: datetime object representing the date that this picture was trasmitted + :param transmission: datetime object representing the date that this picture was transmitted :param status: the status of the request, can only be from the requets in ARORequestStatus """ with get_db_session() as session: @@ -45,8 +67,8 @@ def add_request( longitude=long, created_on=created_on, request_sent_to_obc_on=request_sent_obc, - taken_date=taken_date, - transmission=transmission, + pic_taken_on=taken_date, + pic_transmitted_on=transmission, status=status, ) diff --git a/python_test/test_aro_requests_api.py b/python_test/test_aro_requests_api.py new file mode 100644 index 000000000..f73b5417d --- /dev/null +++ b/python_test/test_aro_requests_api.py @@ -0,0 +1,143 @@ +from datetime import datetime, timedelta, timezone +from decimal import Decimal +from uuid import UUID + +import pytest +from fastapi.testclient import TestClient +from gs.backend.data.data_wrappers.aro_wrapper.aro_request_wrapper import add_request +from gs.backend.data.data_wrappers.aro_wrapper.aro_user_data_wrapper import add_user +from gs.backend.data.enums.aro_requests import ARORequestStatus +from gs.backend.main import app + + +@pytest.fixture +def client(): + return TestClient(app) + + +# Create user for request 1 +@pytest.fixture +def test_user1(): + user = add_user( + call_sign="TEST01", + email="test1@example.com", + f_name="Test", + l_name="User1", + phone_number="1234567890", + ) + return user + + +# Create user for request 2 +@pytest.fixture +def test_user2(): + user = add_user( + call_sign="TEST02", + email="test2@example.com", + f_name="Test", + l_name="User2", + phone_number="0987654321", + ) + return user + + +# Test data for request 1 +@pytest.fixture +def request1_data(test_user1): + created_on = datetime.now() + timedelta(minutes=4) + request_sent_obc = created_on + timedelta(minutes=5) + taken_date = created_on + timedelta(minutes=6) + transmission = created_on + timedelta(minutes=7) + + return { + "aro_id": test_user1.id, + "long": Decimal("123.456"), + "lat": Decimal("49.282"), + "created_on": created_on, + "request_sent_obc": request_sent_obc, + "taken_date": taken_date, + "transmission": transmission, + "status": ARORequestStatus.PENDING, + } + + +# Test data for request 2 +@pytest.fixture +def request2_data(test_user2): + created_on = datetime.now() + request_sent_obc = created_on + timedelta(minutes=1) + taken_date = created_on + timedelta(minutes=2) + transmission = created_on + timedelta(minutes=3) + + return { + "aro_id": test_user2.id, + "long": Decimal("123.456"), + "lat": Decimal("49.282"), + "created_on": created_on, + "request_sent_obc": request_sent_obc, + "taken_date": taken_date, + "transmission": transmission, + "status": ARORequestStatus.COMPLETED, + } + + +# Add request1 to database +@pytest.fixture +def test_request1_creation(client, request1_data): + request = add_request( + aro_id=request1_data["aro_id"], + long=request1_data["long"], + lat=request1_data["lat"], + created_on=request1_data["created_on"], + request_sent_obc=request1_data["request_sent_obc"], + taken_date=request1_data["taken_date"], + transmission=request1_data["transmission"], + status=request1_data["status"], + ) + return request + + +# Add request2 to database +@pytest.fixture +def test_request2_creation(client, request2_data): + request = add_request( + aro_id=request2_data["aro_id"], + long=request2_data["long"], + lat=request2_data["lat"], + created_on=request2_data["created_on"], + request_sent_obc=request2_data["request_sent_obc"], + taken_date=request2_data["taken_date"], + transmission=request2_data["transmission"], + status=request2_data["status"], + ) + return request + + +def test_get_all_requests(client, test_request1_creation, test_request2_creation): + response = client.get( + "/api/v1/mcc/requests?count=2&offset=0&filters=pending&filters=completed", + headers={"Content-Type": "application/json"}, + ) + assert response.status_code == 200 + requests = response.json()["data"] + assert len(requests) == 2 + + request1_response = requests[0] + assert request1_response["aro_id"] == str(test_request1_creation.aro_id) + assert request1_response["longitude"] == str(test_request1_creation.longitude) + assert request1_response["latitude"] == str(test_request1_creation.latitude) + assert request1_response["created_on"] == test_request1_creation.created_on.isoformat() + assert request1_response["request_sent_to_obc_on"] == test_request1_creation.request_sent_to_obc_on.isoformat() + assert request1_response["pic_taken_on"] == test_request1_creation.pic_taken_on.isoformat() + assert request1_response["pic_transmitted_on"] == test_request1_creation.pic_transmitted_on.isoformat() + assert request1_response["status"] == test_request1_creation.status.value + + request2_response = requests[1] + assert request2_response["aro_id"] == str(test_request2_creation.aro_id) + assert request2_response["longitude"] == str(test_request2_creation.longitude) + assert request2_response["latitude"] == str(test_request2_creation.latitude) + assert request2_response["created_on"] == test_request2_creation.created_on.isoformat() + assert request2_response["request_sent_to_obc_on"] == test_request2_creation.request_sent_to_obc_on.isoformat() + assert request2_response["pic_taken_on"] == test_request2_creation.pic_taken_on.isoformat() + assert request2_response["pic_transmitted_on"] == test_request2_creation.pic_transmitted_on.isoformat() + assert request2_response["status"] == test_request2_creation.status.value