diff --git a/docker/python.dockerfile b/docker/python.dockerfile new file mode 100644 index 0000000..b574107 --- /dev/null +++ b/docker/python.dockerfile @@ -0,0 +1,15 @@ +FROM python:3.11-alpine + +RUN pip install poetry + +WORKDIR /app +COPY ../pyproject.toml poetry.lock ./ + +RUN poetry install --without dev + +COPY ../mta_api_client ./ +COPY ../mta_sign_server ./ + +COPY ../main.py stops.txt ./ + +ENTRYPOINT ["poetry", "run", "python", "-m", "annapurna.main"] \ No newline at end of file diff --git a/docker/ui.dockerfile b/docker/ui.dockerfile new file mode 100644 index 0000000..def34cb --- /dev/null +++ b/docker/ui.dockerfile @@ -0,0 +1,4 @@ +FROM ubuntu:latest +LABEL authors="lucasoskorep" + +ENTRYPOINT ["top", "-b"] \ No newline at end of file diff --git a/justfile b/justfile index edc93d5..2a90745 100644 --- a/justfile +++ b/justfile @@ -17,3 +17,6 @@ # Auto fix lint with ruff @lint-fix: poetry run ruff . --fix + +@containers: + podman build -f python.dockerfile -t pi-mta-sign:latest . --load \ No newline at end of file diff --git a/main.py b/main.py index f28cf3f..c7ed18f 100644 --- a/main.py +++ b/main.py @@ -1,4 +1,3 @@ -import json import logging import uvicorn @@ -23,6 +22,5 @@ app.include_router(config_router) logger = logging.getLogger("main") - if __name__ == "__main__": uvicorn.run("main:app", host="0.0.0.0", port=8000, log_level="info", reload=True) diff --git a/mta-sign-ui/components/trains/line.tsx b/mta-sign-ui/components/trains/line.tsx index 127f0d4..aa9366e 100644 --- a/mta-sign-ui/components/trains/line.tsx +++ b/mta-sign-ui/components/trains/line.tsx @@ -1,12 +1,13 @@ 'use client' -import React, {useEffect, useState} from 'react'; -import {fetchStartDate} from "@/services/mta-api/mta-server"; +import React, {useState} from 'react'; +// import {fetchStartDate} from "@/services/mta-api/mta-server"; import {MtaStartTime} from "@/services/mta-api/types"; -import Image from 'next/image'; +// import Image from 'next/image'; +import {RouteResponse} from "@/gen-sources/mta-sign-api"; -const Line = () => { +const Line = (props: RouteResponse) => { // const [data, setData] = useState(null); - + // // useEffect(() => { // const fetchData = async () => { // try { @@ -24,7 +25,7 @@ const Line = () => { return (
- TRAIN LINE HERE + TRAIN LINE HERE - {props.arrival_times.toJSON().toString()}
); }; diff --git a/mta-sign-ui/components/trains/station.tsx b/mta-sign-ui/components/trains/station.tsx index d6cc9ee..fe200fc 100644 --- a/mta-sign-ui/components/trains/station.tsx +++ b/mta-sign-ui/components/trains/station.tsx @@ -1,17 +1,16 @@ 'use client' import React, {useEffect, useState} from 'react'; -import {AllStationModel} from "@/gen-sources/mta-sign-api"; +import {AllStationResponse, StationResponse} from "@/gen-sources/mta-sign-api"; import {mtaDataClient} from "@/services/mta-api/types"; const Station = () => { - const [data, setData] = useState(null); + const [data, setData] = useState(null); useEffect(() => { const fetchData = async () => { try { console.log("CALLING API") const mtaData = await mtaDataClient.getAllApiMtaPost() - const data = mtaData.data - setData(data) + setData(mtaData.data) } catch (error) { console.error('Error fetching data:', error); @@ -27,7 +26,12 @@ const Station = () => {
{data ? ( -

Train Line {data.stations.toString()}

+

+ {data.stations.map(function (station:any, i:any) { + return {station.stationId} + })} + Train Line {} +

) : (

Loading data...

diff --git a/mta-sign-ui/gen-sources/mta-sign-api/api.ts b/mta-sign-ui/gen-sources/mta-sign-api/api.ts index 24ab9d1..c1588ac 100644 --- a/mta-sign-ui/gen-sources/mta-sign-api/api.ts +++ b/mta-sign-ui/gen-sources/mta-sign-api/api.ts @@ -26,15 +26,15 @@ import { BASE_PATH, COLLECTION_FORMATS, BaseAPI, RequiredError } from './base'; /** * * @export - * @interface AllStationModel + * @interface AllStationResponse */ -export interface AllStationModel { +export interface AllStationResponse { /** * - * @type {{ [key: string]: StationResponse; }} - * @memberof AllStationModel + * @type {any} + * @memberof AllStationResponse */ - 'stations': { [key: string]: StationResponse; }; + 'stations': any; } /** * @@ -62,6 +62,12 @@ export interface Route { * @interface RouteResponse */ export interface RouteResponse { + /** + * + * @type {Route} + * @memberof RouteResponse + */ + 'routeId': Route; /** * * @type {any} @@ -69,6 +75,8 @@ export interface RouteResponse { */ 'arrival_times': any; } + + /** * * @export @@ -77,10 +85,16 @@ export interface RouteResponse { export interface StationResponse { /** * - * @type {{ [key: string]: RouteResponse; }} + * @type {any} * @memberof StationResponse */ - 'routes': { [key: string]: RouteResponse; }; + 'stationId': any; + /** + * + * @type {any} + * @memberof StationResponse + */ + 'routes': any; } /** * @@ -330,7 +344,7 @@ export const MtaDataApiFp = function(configuration?: Configuration) { * @param {*} [options] Override http request option. * @throws {RequiredError} */ - async getAllApiMtaPost(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + async getAllApiMtaPost(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { const localVarAxiosArgs = await localVarAxiosParamCreator.getAllApiMtaPost(options); return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); }, @@ -373,7 +387,7 @@ export const MtaDataApiFactory = function (configuration?: Configuration, basePa * @param {*} [options] Override http request option. * @throws {RequiredError} */ - getAllApiMtaPost(options?: any): AxiosPromise { + getAllApiMtaPost(options?: any): AxiosPromise { return localVarFp.getAllApiMtaPost(options).then((request) => request(axios, basePath)); }, /** diff --git a/mta-sign-ui/gen-sources/mta-sign-api/openapi.json b/mta-sign-ui/gen-sources/mta-sign-api/openapi.json index 28fcb7e..086ece5 100644 --- a/mta-sign-ui/gen-sources/mta-sign-api/openapi.json +++ b/mta-sign-ui/gen-sources/mta-sign-api/openapi.json @@ -1 +1 @@ -{"openapi":"3.1.0","info":{"title":"FastAPI","version":"0.1.0"},"paths":{"/api/start_time":{"post":{"tags":["start"],"summary":"Get Start Time","operationId":"get_start_time_api_start_time_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/mta/{stop_id}/{route}":{"post":{"tags":["mta-data"],"summary":"Get Route","operationId":"get_route_api_mta__stop_id___route__post","parameters":[{"required":true,"schema":{"type":"string","title":"Stop Id"},"name":"stop_id","in":"path"},{"required":true,"schema":{"$ref":"#/components/schemas/Route"},"name":"route","in":"path"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RouteResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/mta/{stop_id}":{"post":{"tags":["mta-data"],"summary":"Get Station","operationId":"get_station_api_mta__stop_id__post","parameters":[{"required":true,"schema":{"type":"string","title":"Stop Id"},"name":"stop_id","in":"path"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/mta":{"post":{"tags":["mta-data"],"summary":"Get All","operationId":"get_all_api_mta_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AllStationModel"}}}}}}},"/api/config":{"get":{"tags":["config"],"summary":"Get All","operationId":"get_all_api_config_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}}},"components":{"schemas":{"AllStationModel":{"properties":{"stations":{"additionalProperties":{"$ref":"#/components/schemas/StationResponse"},"type":"object","title":"Stations"}},"type":"object","required":["stations"],"title":"AllStationModel"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"Route":{"enum":["A","C","E","B","D","F","M","G","J","Z","N","Q","R","W","1","2","3","4","5","6","7","L","SIR"],"title":"Route","description":"An enumeration."},"RouteResponse":{"properties":{"arrival_times":{"items":{"type":"integer"},"type":"array","title":"Arrival Times"}},"type":"object","required":["arrival_times"],"title":"RouteResponse"},"StationResponse":{"properties":{"routes":{"additionalProperties":{"$ref":"#/components/schemas/RouteResponse"},"type":"object","title":"Routes"}},"type":"object","required":["routes"],"title":"StationResponse"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"}}}} \ No newline at end of file +{"openapi":"3.1.0","info":{"title":"FastAPI","version":"0.1.0"},"paths":{"/api/start_time":{"post":{"tags":["start"],"summary":"Get Start Time","operationId":"get_start_time_api_start_time_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/mta/{stop_id}/{route}":{"post":{"tags":["mta-data"],"summary":"Get Route","operationId":"get_route_api_mta__stop_id___route__post","parameters":[{"required":true,"schema":{"type":"string","title":"Stop Id"},"name":"stop_id","in":"path"},{"required":true,"schema":{"$ref":"#/components/schemas/Route"},"name":"route","in":"path"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RouteResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/mta/{stop_id}":{"post":{"tags":["mta-data"],"summary":"Get Station","operationId":"get_station_api_mta__stop_id__post","parameters":[{"required":true,"schema":{"type":"string","title":"Stop Id"},"name":"stop_id","in":"path"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/mta":{"post":{"tags":["mta-data"],"summary":"Get All","operationId":"get_all_api_mta_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AllStationResponse"}}}}}}},"/api/config":{"get":{"tags":["config"],"summary":"Get All","operationId":"get_all_api_config_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}}},"components":{"schemas":{"AllStationResponse":{"properties":{"stations":{"items":{"$ref":"#/components/schemas/StationResponse"},"type":"array","title":"Stations"}},"type":"object","required":["stations"],"title":"AllStationResponse"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"Route":{"enum":["A","C","E","B","D","F","M","G","J","Z","N","Q","R","W","1","2","3","4","5","6","7","L","SIR"],"title":"Route","description":"An enumeration."},"RouteResponse":{"properties":{"routeId":{"$ref":"#/components/schemas/Route"},"arrival_times":{"items":{"type":"integer"},"type":"array","title":"Arrival Times"}},"type":"object","required":["routeId","arrival_times"],"title":"RouteResponse"},"StationResponse":{"properties":{"stationId":{"type":"string","title":"Stationid"},"routes":{"items":{"$ref":"#/components/schemas/RouteResponse"},"type":"array","title":"Routes"}},"type":"object","required":["stationId","routes"],"title":"StationResponse"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"}}}} \ No newline at end of file diff --git a/mta-sign-ui/package.json b/mta-sign-ui/package.json index 5c8c278..6bafbe5 100644 --- a/mta-sign-ui/package.json +++ b/mta-sign-ui/package.json @@ -7,7 +7,8 @@ "build": "next build", "start": "next start", "lint": "next lint", - "gen-apis": "rm -rf ./gen-sources/mta-sign-api/* && curl localhost:8000/openapi.json -O --output-dir ./gen-sources/mta-sign-api && openapi-generator-cli generate" + "gen-apis-old": "rm -rf ./gen-sources/mta-sign-api/* && curl localhost:8000/openapi.json -O --output-dir ./gen-sources/mta-sign-api && openapi-generator-cli generate", + "gen-apis": "npx openapi-typescript http://localhost:8000/openapi.json --output gen-sources/mtaserver.ts" }, "dependencies": { "@types/node": "^20.4.2", @@ -19,6 +20,7 @@ "eslint-config-next": "^13.4.10", "follow-redirects": "^1.15.2", "next": "^13.4.10", + "openapi-typescript-fetch": "^1.1.3", "postcss": "^8.4.26", "react": "^18.2.0", "react-dom": "^18.2.0", diff --git a/mta-sign-ui/yarn.lock b/mta-sign-ui/yarn.lock index 6ce2ec2..28e5b5c 100644 --- a/mta-sign-ui/yarn.lock +++ b/mta-sign-ui/yarn.lock @@ -3231,6 +3231,7 @@ __metadata: eslint-config-next: ^13.4.10 follow-redirects: ^1.15.2 next: ^13.4.10 + openapi-typescript-fetch: ^1.1.3 postcss: ^8.4.26 react: ^18.2.0 react-dom: ^18.2.0 @@ -3558,6 +3559,13 @@ __metadata: languageName: node linkType: hard +"openapi-typescript-fetch@npm:^1.1.3": + version: 1.1.3 + resolution: "openapi-typescript-fetch@npm:1.1.3" + checksum: df3171b0b1e8a99f2bdfb794b4dc348a1f4e5db184fabc7578a810236a5deb7bc7885240ecb2463c03d94707434784c48bd8256ea715b381f5ff91fb9218c7b6 + languageName: node + linkType: hard + "optionator@npm:^0.9.3": version: 0.9.3 resolution: "optionator@npm:0.9.3" diff --git a/mta_sign_server/mta/router.py b/mta_sign_server/mta/router.py index 044fa4d..7d6b3ad 100644 --- a/mta_sign_server/mta/router.py +++ b/mta_sign_server/mta/router.py @@ -6,7 +6,7 @@ from fastapi_utils.tasks import repeat_every from starlette import status from mta_api_client import Route, MTA, Feed -from mta_sign_server.mta.schemas import StationResponse, RouteResponse, AllStationModel +from mta_sign_server.mta.schemas import StationResponse, RouteResponse, AllStationResponse router = APIRouter( tags=["mta-data"], @@ -45,19 +45,20 @@ def get_station(stop_id: str): raise HTTPException(status_code=404, detail="no trains or routes found for stop id") -@router.post("/api/mta", response_model=AllStationModel, status_code=status.HTTP_200_OK) +@router.post("/api/mta", response_model=AllStationResponse, status_code=status.HTTP_200_OK) def get_all(): print("HELLO WORLD") - all_stations = {} + all_stations = [] for stop_id in STATION_STOP_IDs: - routes = {} + routes = [] for route in ROUTES: arrival_times = mtaController.get_arrival_times(route, stop_id) if len(arrival_times) > 0: - routes[route] = RouteResponse(arrival_times=arrival_times) - all_stations[stop_id] = StationResponse(routes=routes) + routes.append(RouteResponse(routeId=route, arrival_times=arrival_times)) + all_stations.append(StationResponse(stationId=stop_id, routes=routes)) + print(all_stations) if all_stations: - return AllStationModel(stations=all_stations) + return AllStationResponse(stations=all_stations) raise HTTPException(status_code=404, detail="no arriving trains found for all configured routes") diff --git a/mta_sign_server/mta/schemas.py b/mta_sign_server/mta/schemas.py index e28a142..e808720 100644 --- a/mta_sign_server/mta/schemas.py +++ b/mta_sign_server/mta/schemas.py @@ -1,16 +1,18 @@ from pydantic import BaseModel -from typing import List, Dict +from typing import List from mta_api_client import Route class RouteResponse(BaseModel): + routeId: Route arrival_times: List[int] class StationResponse(BaseModel): - routes: Dict[Route, RouteResponse] + stationId: str + routes: List[RouteResponse] -class AllStationModel(BaseModel): - stations: Dict[str, StationResponse] +class AllStationResponse(BaseModel): + stations: List[StationResponse]