diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 55aa9100..e65248a3 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -20,9 +20,9 @@ concurrency: env: ROBOLIST_ENVIRONMENT: local JWT_SECRET: test - AWS_ACCESS_KEY_ID: test - AWS_SECRET_ACCESS_KEY: test - AWS_ENDPOINT_URL_DYNAMODB: http://localhost:8000 + AWS_ACCESS_KEY_ID: something + AWS_SECRET_ACCESS_KEY: something + AWS_ENDPOINT_URL_DYNAMODB: http://localhost:8001 AWS_REGION: us-east-1 jobs: diff --git a/frontend/src/hooks/rob.tsx b/frontend/src/hooks/rob.tsx new file mode 100644 index 00000000..9e33720b --- /dev/null +++ b/frontend/src/hooks/rob.tsx @@ -0,0 +1,26 @@ +import axios from "axios"; + +class rob { + private api; + + constructor(baseURL: string | undefined) { + this.api = axios.create({ baseURL }); + } + + public async getRobotById(robotId: string | undefined): Promise { + try { + const response = await this.api.get(`/robots/${robotId}`); + return response.data; + } catch (error) { + if (axios.isAxiosError(error)) { + console.error("Error fetching robot:", error.response?.data); + throw new Error(error.response?.data?.detail || "Error fetching robot"); + } else { + console.error("Unexpected error:", error); + throw new Error("Unexpected error"); + } + } + } +} + +export default new rob("http://127.0.0.1:8080/api"); diff --git a/frontend/src/pages/RobotDetails.tsx b/frontend/src/pages/RobotDetails.tsx index 596d7046..4d135c70 100644 --- a/frontend/src/pages/RobotDetails.tsx +++ b/frontend/src/pages/RobotDetails.tsx @@ -1,4 +1,7 @@ -import { useState } from "react"; +import axios from "axios"; +import { BACKEND_URL } from "constants/backend"; +import rob from "hooks/rob"; +import { useEffect, useState } from "react"; import { Breadcrumb, Button, @@ -22,68 +25,105 @@ interface RobotDetailsResponse { const RobotDetails = () => { const { id } = useParams(); const [show, setShow] = useState(false); + const [robot, setRobot] = useState(null); const [imageIndex, setImageIndex] = useState(0); + const [error, setError] = useState(null); const handleClose = () => setShow(false); const handleShow = () => setShow(true); + const api = axios.create({ + baseURL: BACKEND_URL, + withCredentials: true, + }); + useEffect(() => { + const fetchRobot = async () => { + try { + const robotData = await rob.getRobotById(id); + setRobot(robotData); + } catch (err) { + // Handle error + if (err instanceof Error) { + setError(err.message); + } else { + setError("An unknown error occurred"); + } + } + }; + fetchRobot(); + }, [id]); + + if (error) { + return ( +
+

Oopsie Daisies ! Something went wrong

+

{error}

+
+ ); + } + + if (!robot) { + return
Loading...
; + } + + const response: RobotDetailsResponse = robot; // This is a placeholder before the backend is hooked up. - const response: RobotDetailsResponse = { - name: "Stompy", - owner: "K-Scale Labs", - description: `Stompy is an open-source humanoid robot that anyone can 3D print. - -## Purpose - -Stompy is designed to be a versatile platform for research and development in legged robotics. - -## Links - -- [Wiki Entry](https://humanoids.wiki/w/Stompy) - -### Full Body Sim Artifacts - -- [URDF (with STLs)](https://media.kscale.dev/stompy/latest_stl_urdf.tar.gz) -- [URDF (with OBJs)](https://media.kscale.dev/stompy/latest_obj_urdf.tar.gz) -- [MJCF](https://media.kscale.dev/stompy/latest_mjcf.tar.gz) - -### Single Arm Sim Artifacts - -- [URDF (with STLs)](https://media.kscale.dev/stompy/arm_latest_stl_urdf.tar.gz) -- [URDF (with OBJs)](https://media.kscale.dev/stompy/arm_latest_obj_urdf.tar.gz) -- [MJCF](https://media.kscale.dev/stompy/arm_latest_mjcf.tar.gz) -`, - images: [ - { - url: "https://media.robolist.xyz/stompy.png", - caption: "Stompy the robot 1", - }, - { - url: "https://media.robolist.xyz/stompy.png", - caption: "Stompy the robot 2", - }, - { - url: "https://media.robolist.xyz/stompy.png", - caption: "Stompy the robot 3", - }, - ], - bom: [ - { - name: "Actuator", - id: "1234", - quantity: 10, - price: 100, - }, - { - name: "Sensor", - id: "5678", - quantity: 5, - price: 50, - }, - ], - }; - - const { name, owner, description, images } = response; + // const response: RobotDetailsResponse = { + // name: "Stompy", + // owner: "K-Scale Labs", + // description: `Stompy is an open-source humanoid robot that anyone can 3D print. + + // ## Purpose + + // Stompy is designed to be a versatile platform for research and development in legged robotics. + + // ## Links + + // - [Wiki Entry](https://humanoids.wiki/w/Stompy) + + // ### Full Body Sim Artifacts + + // - [URDF (with STLs)](https://media.kscale.dev/stompy/latest_stl_urdf.tar.gz) + // - [URDF (with OBJs)](https://media.kscale.dev/stompy/latest_obj_urdf.tar.gz) + // - [MJCF](https://media.kscale.dev/stompy/latest_mjcf.tar.gz) + + // ### Single Arm Sim Artifacts + + // - [URDF (with STLs)](https://media.kscale.dev/stompy/arm_latest_stl_urdf.tar.gz) + // - [URDF (with OBJs)](https://media.kscale.dev/stompy/arm_latest_obj_urdf.tar.gz) + // - [MJCF](https://media.kscale.dev/stompy/arm_latest_mjcf.tar.gz) + // `, + // images: [ + // { + // url: "https://media.robolist.xyz/stompy.png", + // caption: "Stompy the robot 1", + // }, + // { + // url: "https://media.robolist.xyz/stompy.png", + // caption: "Stompy the robot 2", + // }, + // { + // url: "https://media.robolist.xyz/stompy.png", + // caption: "Stompy the robot 3", + // }, + // ], + // bom: [ + // { + // name: "Actuator", + // id: "1234", + // quantity: 10, + // price: 100, + // }, + // { + // name: "Sensor", + // id: "5678", + // quantity: 5, + // price: 50, + // }, + // ], + // }; + + const { name, owner, description, images } = robot; const navigate = useNavigate(); diff --git a/store/app/api/email.py b/store/app/api/email_utils.py similarity index 97% rename from store/app/api/email.py rename to store/app/api/email_utils.py index 857a5749..f66b847f 100644 --- a/store/app/api/email.py +++ b/store/app/api/email_utils.py @@ -11,7 +11,7 @@ import aiosmtplib -from store.app.api.token import create_token, load_token +from store.app.api.token_utils import create_token, load_token from store.settings import settings logger = logging.getLogger(__name__) diff --git a/store/app/api/getR.py b/store/app/api/getR.py new file mode 100644 index 00000000..2ba58095 --- /dev/null +++ b/store/app/api/getR.py @@ -0,0 +1,39 @@ +# from typing import Union + +# import boto3 +# from botocore.exceptions import ClientError +# from fastapi import FastAPI, HTTPException +# from pydantic import BaseModel + +# app = FastAPI() + +# # Configure your DynamoDB client +# dynamodb = boto3.resource( +# "dynamodb", +# region_name="us-east-1", # Replace with your AWS region +# aws_access_key_id="test", # Replace with your AWS access key +# aws_secret_access_key="test", # Replace with your AWS secret key +# ) + +# # Replace 'Robots' with your DynamoDB table name +# table = dynamodb.Table("Robots") + + +# class Robot(BaseModel): +# robot_id: str +# name: str +# description: str +# owner: str + + +# @app.get("/robots/{robot_id}", response_model=Robot) +# async def get_robot(robot_id: str) -> Union[Robot, HTTPException]: +# try: +# response = table.get_item(Key={"robot_id": robot_id}) +# if "Item" in response: +# robot = response["Item"] +# return Robot(**robot) +# else: +# raise HTTPException(status_code=404, detail="Robot not found") +# except ClientError as e: +# raise HTTPException(status_code=500, detail=e.response["Error"]["Message"]) diff --git a/store/app/api/routers/main.py b/store/app/api/routers/main.py index e65a241f..5a613ce2 100644 --- a/store/app/api/routers/main.py +++ b/store/app/api/routers/main.py @@ -1,18 +1,56 @@ """Defines the main API endpoint.""" import logging +from typing import Union -from fastapi import APIRouter, HTTPException, status +import boto3 +from botocore.exceptions import ClientError +from fastapi import APIRouter, FastAPI, HTTPException, status +from pydantic import BaseModel from store.app.api.routers.users import users_router logger = logging.getLogger(__name__) +app = FastAPI() + api_router = APIRouter() api_router.include_router(users_router, prefix="/users", tags=["users"]) +# Configure your DynamoDB client +dynamodb = boto3.resource( + "dynamodb", + region_name="us-east-1", # Replace with your AWS region + aws_access_key_id="something", # Replace with your AWS access key + aws_secret_access_key="something", # Replace with your AWS secret key +) + +# Replace 'Robots' with your DynamoDB table name +table = dynamodb.Table("Robots") + + +class Robot(BaseModel): + robot_id: str + name: str + description: str + owner: str + + +@api_router.get("/robots/{robot_id}", response_model=Robot) +async def get_robot(robot_id: str) -> Union[Robot, HTTPException]: + try: + response = table.get_item(Key={"robot_id": robot_id}) + if "Item" in response: + robot = response["Item"] + return Robot(**robot) + else: + raise HTTPException(status_code=404, detail="Robot not found {response} ooga booga") + except ClientError as e: + raise HTTPException(status_code=500, detail=e.response["Error"]["Message"]) + + # Returns a 404 response for all other paths. @api_router.get("/{path:path}") async def not_found(path: str) -> dict[str, str]: diff --git a/store/app/api/routers/users.py b/store/app/api/routers/users.py index f27e43aa..6b2f48c7 100644 --- a/store/app/api/routers/users.py +++ b/store/app/api/routers/users.py @@ -12,9 +12,9 @@ from pydantic.main import BaseModel from store.app.api.db import Crud -from store.app.api.email import OneTimePassPayload, send_delete_email, send_otp_email +from store.app.api.email_utils import OneTimePassPayload, send_delete_email, send_otp_email from store.app.api.model import User -from store.app.api.token import create_refresh_token, create_token, load_refresh_token, load_token +from store.app.api.token_utils import create_refresh_token, create_token, load_refresh_token, load_token from store.settings import settings logger = logging.getLogger(__name__) diff --git a/store/app/api/testCred.py b/store/app/api/testCred.py new file mode 100644 index 00000000..af268477 --- /dev/null +++ b/store/app/api/testCred.py @@ -0,0 +1,20 @@ +import boto3 +from botocore.exceptions import NoCredentialsError, PartialCredentialsError + + +def test_dynamodb_connection() -> None: + try: + # Initialize DynamoDB client + dynamodb = boto3.resource('dynamodb') + # Attempt to list tables as a test + tables = list(dynamodb.tables.all()) + print(f"Connected to DynamoDB. Found tables: {[table.name for table in tables]}") + except NoCredentialsError: + print("No credentials found. Please configure your AWS credentials.") + except PartialCredentialsError: + print("Incomplete credentials found. Please check your AWS credentials.") + except Exception as e: + print(f"An error occurred: {e}") + +if __name__ == "__main__": + test_dynamodb_connection() diff --git a/store/app/api/token.py b/store/app/api/token_utils.py similarity index 100% rename from store/app/api/token.py rename to store/app/api/token_utils.py