-
Notifications
You must be signed in to change notification settings - Fork 590
Initial #12
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Initial #12
Changes from 15 commits
5e224b4
2d965c1
4e11cca
29610bd
e08d5b5
952cf6a
f1b0c0d
0e5f691
a46b140
8431896
5ae8d5b
7d8636f
7b85afd
f7f63f7
4d34a94
d66acea
222dcbe
a0a3d29
aeb7342
ca7392a
27610c3
c7cc00e
4d2ca01
bd99590
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| # Virtual environment | ||
| venv/ | ||
|
|
||
| # Python cache files | ||
| __pycache__/ | ||
| *.pyc | ||
| *.pyo | ||
| *.pyd | ||
|
|
||
| # Logs & temp files | ||
| *.log | ||
| *.tmp | ||
| *.swp | ||
| *.swo | ||
|
|
||
| # IDE/Editor files | ||
| .vscode/ | ||
| .idea/ | ||
|
|
||
| # Environment variables (if needed) | ||
| .env | ||
|
|
||
| # OS-specific files | ||
| .DS_Store | ||
| Thumbs.db |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| from fastapi import FastAPI | ||
| from app.routes import auth, donor, organisation | ||
|
|
||
| app = FastAPI() | ||
|
|
||
| app.include_router(auth.router, prefix="/auth", tags=["Auth"]) | ||
| app.include_router(donor.router, prefix="/donor", tags=["Donor"]) | ||
| app.include_router(organisation.router, prefix="/organisation", tags=["Organisation"]) | ||
|
|
||
| @app.get("/") | ||
| def home(): | ||
| return {"message": "Welcome to the FastAPI Backend (No Database)"} | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,28 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from fastapi import APIRouter, HTTPException | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from pydantic import BaseModel | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from passlib.context import CryptContext | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| router = APIRouter() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| users = [] # In-memory storage | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| class UserCreate(BaseModel): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| name: str | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| email: str | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| password: str | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+23
to
+26
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Add input validation for user fields. The current model lacks validation for email format and password strength. Apply this diff to add validation: +from pydantic import BaseModel, EmailStr, Field
+import re
+
+def validate_password(v: str) -> str:
+ if not re.match(r'^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{8,}$', v):
+ raise ValueError('Password must be at least 8 characters long and contain both letters and numbers')
+ return v
+
class UserCreate(BaseModel):
name: str
- email: str
- password: str
+ email: EmailStr
+ password: str = Field(..., min_length=8)
+
+ @validator('password')
+ def password_validation(cls, v):
+ return validate_password(v)
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @router.post("/register") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def register(user: UserCreate): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for u in users: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if u["email"] == user.email: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| raise HTTPException(status_code=400, detail="Email already exists") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| hashed_password = pwd_context.hash(user.password) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| new_user = {"name": user.name, "email": user.email, "password": hashed_password} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| users.append(new_user) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return {"message": "User registered successfully"} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @router.post("/login") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def login(): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return {"message": "Login endpoint (To be implemented)"} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @router.post("/login") | |
| def login(): | |
| return {"message": "Login endpoint (To be implemented)"} | |
| from datetime import datetime, timedelta | |
| from jose import JWTError, jwt | |
| from fastapi.security import OAuth2PasswordBearer | |
| SECRET_KEY = "your-secret-key" # Move to environment variables | |
| ALGORITHM = "HS256" | |
| ACCESS_TOKEN_EXPIRE_MINUTES = 30 | |
| oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token") | |
| @router.post("/login") | |
| async def login(email: str, password: str): | |
| user = next((u for u in users if u["email"] == email), None) | |
| if not user or not pwd_context.verify(password, user["password"]): | |
| raise HTTPException( | |
| status_code=401, | |
| detail="Incorrect email or password", | |
| headers={"WWW-Authenticate": "Bearer"}, | |
| ) | |
| access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES) | |
| access_token = create_access_token( | |
| data={"sub": user["email"]}, expires_delta=access_token_expires | |
| ) | |
| return {"access_token": access_token, "token_type": "bearer"} | |
| def create_access_token(data: dict, expires_delta: timedelta): | |
| to_encode = data.copy() | |
| expire = datetime.utcnow() + expires_delta | |
| to_encode.update({"exp": expire}) | |
| encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM) | |
| return encoded_jwt |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,15 @@ | ||||||||||||||||||||||||||||||||
| from fastapi import APIRouter | ||||||||||||||||||||||||||||||||
| from pydantic import BaseModel | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| router = APIRouter() | ||||||||||||||||||||||||||||||||
| donors = [] # In-memory storage | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| class DonorCreate(BaseModel): | ||||||||||||||||||||||||||||||||
| name: str | ||||||||||||||||||||||||||||||||
| age: int | ||||||||||||||||||||||||||||||||
| contact: str | ||||||||||||||||||||||||||||||||
|
Comment on lines
+7
to
+10
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Add input validation for age and contact fields. The current model lacks validation constraints. Consider adding:
Apply this diff to add validation: class DonorCreate(BaseModel):
name: str
- age: int
- contact: str
+ age: int = Field(..., gt=0, lt=150)
+ contact: str = Field(..., regex=r'^\+?1?\d{9,15}$')📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| @router.post("/register") | ||||||||||||||||||||||||||||||||
| def register_donor(donor: DonorCreate): | ||||||||||||||||||||||||||||||||
| donors.append(donor.dict()) | ||||||||||||||||||||||||||||||||
| return {"message": "Donor registered successfully", "donor": donor} | ||||||||||||||||||||||||||||||||
|
Comment on lines
+12
to
+15
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Add error handling and implement GET endpoint. The current implementation lacks error handling and a way to retrieve donor information. Add error handling and a GET endpoint: +@router.get("/")
+def get_donors():
+ return {"donors": donors}
+
@router.post("/register")
-def register_donor(donor: DonorCreate):
+async def register_donor(donor: DonorCreate):
+ try:
donors.append(donor.dict())
return {"message": "Donor registered successfully", "donor": donor}
+ except Exception as e:
+ raise HTTPException(status_code=500, detail=str(e))📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,19 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from fastapi import APIRouter | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from pydantic import BaseModel | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| router = APIRouter() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| organisations = [] # In-memory storage | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| class OrganisationCreate(BaseModel): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| name: str | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| description: str | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| contact: str | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+7
to
+10
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Add input validation for organisation fields. The current model lacks validation constraints for contact and description fields. Apply this diff to add validation: class OrganisationCreate(BaseModel):
- name: str
- description: str
- contact: str
+ name: str = Field(..., min_length=1, max_length=100)
+ description: str = Field(..., min_length=10, max_length=1000)
+ contact: str = Field(..., regex=r'^\+?1?\d{9,15}$')📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @router.post("/register") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def register_organisation(org: OrganisationCreate): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| organisations.append(org.dict()) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return {"message": "Organisation registered successfully", "organisation": org} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @router.get("/") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def get_organisations(): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return {"organisations": organisations} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+12
to
+19
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Add error handling and CRUD operations. The current implementation lacks error handling and complete CRUD operations. Add error handling and additional endpoints: +from fastapi import HTTPException
+
@router.post("/register")
-def register_organisation(org: OrganisationCreate):
+async def register_organisation(org: OrganisationCreate):
+ try:
organisations.append(org.dict())
return {"message": "Organisation registered successfully", "organisation": org}
+ except Exception as e:
+ raise HTTPException(status_code=500, detail=str(e))
@router.get("/")
-def get_organisations():
+async def get_organisations():
return {"organisations": organisations}
+
+@router.put("/{org_id}")
+async def update_organisation(org_id: int, org: OrganisationCreate):
+ if org_id >= len(organisations):
+ raise HTTPException(status_code=404, detail="Organisation not found")
+ organisations[org_id] = org.dict()
+ return {"message": "Organisation updated successfully"}
+
+@router.delete("/{org_id}")
+async def delete_organisation(org_id: int):
+ if org_id >= len(organisations):
+ raise HTTPException(status_code=404, detail="Organisation not found")
+ organisations.pop(org_id)
+ return {"message": "Organisation deleted successfully"}📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. | ||
|
|
||
| # dependencies | ||
| /node_modules | ||
| /.pnp | ||
| .pnp.js | ||
|
|
||
| # testing | ||
| /coverage | ||
|
|
||
| # production | ||
| /build | ||
|
|
||
| # misc | ||
| .DS_Store | ||
| .env.local | ||
| .env.development.local | ||
| .env.test.local | ||
| .env.production.local | ||
|
|
||
| npm-debug.log* | ||
| yarn-debug.log* | ||
| yarn-error.log* |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,70 @@ | ||
| # Getting Started with Create React App | ||
|
|
||
| This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). | ||
|
|
||
| ## Available Scripts | ||
|
|
||
| In the project directory, you can run: | ||
|
|
||
| ### `npm start` | ||
|
|
||
| Runs the app in the development mode.\ | ||
| Open [http://localhost:3000](http://localhost:3000) to view it in your browser. | ||
|
|
||
| The page will reload when you make changes.\ | ||
| You may also see any lint errors in the console. | ||
|
|
||
| ### `npm test` | ||
|
|
||
| Launches the test runner in the interactive watch mode.\ | ||
| See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. | ||
|
|
||
| ### `npm run build` | ||
|
|
||
| Builds the app for production to the `build` folder.\ | ||
| It correctly bundles React in production mode and optimizes the build for the best performance. | ||
|
|
||
| The build is minified and the filenames include the hashes.\ | ||
| Your app is ready to be deployed! | ||
|
|
||
| See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. | ||
|
|
||
| ### `npm run eject` | ||
|
|
||
| **Note: this is a one-way operation. Once you `eject`, you can't go back!** | ||
|
|
||
| If you aren't satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. | ||
|
|
||
| Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you're on your own. | ||
|
|
||
| You don't have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn't feel obligated to use this feature. However we understand that this tool wouldn't be useful if you couldn't customize it when you are ready for it. | ||
|
|
||
| ## Learn More | ||
|
|
||
| You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). | ||
|
|
||
| To learn React, check out the [React documentation](https://reactjs.org/). | ||
|
|
||
| ### Code Splitting | ||
|
|
||
| This section has moved here: [https://facebook.github.io/create-react-app/docs/code-splitting](https://facebook.github.io/create-react-app/docs/code-splitting) | ||
|
|
||
| ### Analyzing the Bundle Size | ||
|
|
||
| This section has moved here: [https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size](https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size) | ||
|
|
||
| ### Making a Progressive Web App | ||
|
|
||
| This section has moved here: [https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app](https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app) | ||
|
|
||
| ### Advanced Configuration | ||
|
|
||
| This section has moved here: [https://facebook.github.io/create-react-app/docs/advanced-configuration](https://facebook.github.io/create-react-app/docs/advanced-configuration) | ||
|
|
||
| ### Deployment | ||
|
|
||
| This section has moved here: [https://facebook.github.io/create-react-app/docs/deployment](https://facebook.github.io/create-react-app/docs/deployment) | ||
|
|
||
| ### `npm run build` fails to minify | ||
|
|
||
| This section has moved here: [https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify](https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Add CORS middleware and API versioning.
To support frontend integration and API versioning:
Apply this diff:
📝 Committable suggestion