|
| 1 | +from fastapi import FastAPI, Depends, HTTPException, status |
| 2 | +from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm |
| 3 | +from sqlalchemy.orm import Session |
| 4 | +from typing import List |
| 5 | + |
| 6 | +import models |
| 7 | +import schemas |
| 8 | +import auth |
| 9 | +from database import SessionLocal, engine, get_db |
| 10 | +from jose import JWTError, jwt |
| 11 | + |
| 12 | +models.Base.metadata.create_all(bind=engine) |
| 13 | + |
| 14 | +app = FastAPI(title="Python Dashboard API") |
| 15 | + |
| 16 | +oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token") |
| 17 | + |
| 18 | +def get_user_by_email(db: Session, email: str): |
| 19 | + return db.query(models.User).filter(models.User.email == email).first() |
| 20 | + |
| 21 | +async def get_current_user(token: str = Depends(oauth2_scheme), db: Session = Depends(get_db)): |
| 22 | + credentials_exception = HTTPException( |
| 23 | + status_code=status.HTTP_401_UNAUTHORIZED, |
| 24 | + detail="Could not validate credentials", |
| 25 | + headers={"WWW-Authenticate": "Bearer"}, |
| 26 | + ) |
| 27 | + try: |
| 28 | + payload = jwt.decode(token, auth.SECRET_KEY, algorithms=[auth.ALGORITHM]) |
| 29 | + email: str = payload.get("sub") |
| 30 | + if email is None: |
| 31 | + raise credentials_exception |
| 32 | + token_data = schemas.TokenData(email=email) |
| 33 | + except JWTError: |
| 34 | + raise credentials_exception |
| 35 | + user = get_user_by_email(db, email=token_data.email) |
| 36 | + if user is None: |
| 37 | + raise credentials_exception |
| 38 | + return user |
| 39 | + |
| 40 | +# --- Auth Endpoints --- |
| 41 | + |
| 42 | +@app.post("/register", response_model=schemas.User) |
| 43 | +def register_user(user: schemas.UserCreate, db: Session = Depends(get_db)): |
| 44 | + db_user = get_user_by_email(db, email=user.email) |
| 45 | + if db_user: |
| 46 | + raise HTTPException(status_code=400, detail="Email already registered") |
| 47 | + hashed_password = auth.get_password_hash(user.password) |
| 48 | + new_user = models.User(email=user.email, hashed_password=hashed_password) |
| 49 | + db.add(new_user) |
| 50 | + db.commit() |
| 51 | + db.refresh(new_user) |
| 52 | + return new_user |
| 53 | + |
| 54 | +@app.post("/token", response_model=schemas.Token) |
| 55 | +def login_for_access_token(form_data: OAuth2PasswordRequestForm = Depends(), db: Session = Depends(get_db)): |
| 56 | + user = get_user_by_email(db, email=form_data.username) |
| 57 | + if not user or not auth.verify_password(form_data.password, user.hashed_password): |
| 58 | + raise HTTPException( |
| 59 | + status_code=status.HTTP_401_UNAUTHORIZED, |
| 60 | + detail="Incorrect username or password", |
| 61 | + headers={"WWW-Authenticate": "Bearer"}, |
| 62 | + ) |
| 63 | + access_token_expires = auth.timedelta(minutes=auth.ACCESS_TOKEN_EXPIRE_MINUTES) |
| 64 | + access_token = auth.create_access_token( |
| 65 | + data={"sub": user.email}, expires_delta=access_token_expires |
| 66 | + ) |
| 67 | + return {"access_token": access_token, "token_type": "bearer"} |
| 68 | + |
| 69 | +# --- Dashboard CRUD Endpoints --- |
| 70 | + |
| 71 | +@app.post("/items/", response_model=schemas.Item) |
| 72 | +def create_item(item: schemas.ItemCreate, db: Session = Depends(get_db), current_user: models.User = Depends(get_current_user)): |
| 73 | + db_item = models.Item(**item.model_dump(), owner_id=current_user.id) |
| 74 | + db.add(db_item) |
| 75 | + db.commit() |
| 76 | + db.refresh(db_item) |
| 77 | + return db_item |
| 78 | + |
| 79 | +@app.get("/items/", response_model=List[schemas.Item]) |
| 80 | +def read_items(skip: int = 0, limit: int = 100, db: Session = Depends(get_db), current_user: models.User = Depends(get_current_user)): |
| 81 | + items = db.query(models.Item).filter(models.Item.owner_id == current_user.id).offset(skip).limit(limit).all() |
| 82 | + return items |
| 83 | + |
| 84 | +@app.put("/items/{item_id}", response_model=schemas.Item) |
| 85 | +def update_item(item_id: int, item: schemas.ItemCreate, db: Session = Depends(get_db), current_user: models.User = Depends(get_current_user)): |
| 86 | + db_item = db.query(models.Item).filter(models.Item.id == item_id, models.Item.owner_id == current_user.id).first() |
| 87 | + if not db_item: |
| 88 | + raise HTTPException(status_code=404, detail="Item not found") |
| 89 | + |
| 90 | + for key, value in item.model_dump().items(): |
| 91 | + setattr(db_item, key, value) |
| 92 | + |
| 93 | + db.commit() |
| 94 | + db.refresh(db_item) |
| 95 | + return db_item |
| 96 | + |
| 97 | +@app.delete("/items/{item_id}") |
| 98 | +def delete_item(item_id: int, db: Session = Depends(get_db), current_user: models.User = Depends(get_current_user)): |
| 99 | + db_item = db.query(models.Item).filter(models.Item.id == item_id, models.Item.owner_id == current_user.id).first() |
| 100 | + if not db_item: |
| 101 | + raise HTTPException(status_code=404, detail="Item not found") |
| 102 | + |
| 103 | + db.delete(db_item) |
| 104 | + db.commit() |
| 105 | + return {"detail": "Item deleted"} |
| 106 | + |
| 107 | +@app.get("/users/me/", response_model=schemas.User) |
| 108 | +def read_users_me(current_user: models.User = Depends(get_current_user)): |
| 109 | + return current_user |
0 commit comments