Skip to content

Commit 90041dc

Browse files
committed
Backend files added
1 parent 646017b commit 90041dc

5 files changed

Lines changed: 195 additions & 0 deletions

File tree

‎assets/backend/database.py‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
from sqlalchemy import create_engine
2+
from sqlalchemy.orm import declarative_base
3+
from sqlalchemy.orm import sessionmaker
4+
5+
SQLALCHEMY_DATABASE_URL = "sqlite:///./dashboard.db"
6+
7+
engine = create_engine(
8+
SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False}
9+
)
10+
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
11+
12+
Base = declarative_base()
13+
14+
def get_db():
15+
db = SessionLocal()
16+
try:
17+
yield db
18+
finally:
19+
db.close()

‎assets/backend/main.py‎

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
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

‎assets/backend/models.py‎

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
from sqlalchemy import Column, Integer, String, Float, ForeignKey
2+
from sqlalchemy.orm import relationship
3+
from database import Base
4+
5+
class User(Base):
6+
__tablename__ = "users"
7+
8+
id = Column(Integer, primary_key=True, index=True)
9+
email = Column(String, unique=True, index=True)
10+
hashed_password = Column(String)
11+
12+
items = relationship("Item", back_populates="owner")
13+
14+
class Item(Base):
15+
__tablename__ = "items"
16+
17+
id = Column(Integer, primary_key=True, index=True)
18+
title = Column(String, index=True)
19+
description = Column(String, index=True)
20+
value = Column(Float, default=0.0)
21+
owner_id = Column(Integer, ForeignKey("users.id"))
22+
23+
owner = relationship("User", back_populates="items")

‎assets/backend/requirements.txt‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
fastapi
2+
uvicorn
3+
sqlalchemy
4+
pydantic
5+
python-jose[cryptography]
6+
passlib[bcrypt]
7+
python-multipart

‎assets/backend/schemas.py‎

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
from pydantic import BaseModel
2+
from typing import List, Optional
3+
4+
class ItemBase(BaseModel):
5+
title: str
6+
description: Optional[str] = None
7+
value: float = 0.0
8+
9+
class ItemCreate(ItemBase):
10+
pass
11+
12+
class Item(ItemBase):
13+
id: int
14+
owner_id: int
15+
16+
class Config:
17+
from_attributes = True
18+
19+
class UserBase(BaseModel):
20+
email: str
21+
22+
class UserCreate(UserBase):
23+
password: str
24+
25+
class User(UserBase):
26+
id: int
27+
items: List[Item] = []
28+
29+
class Config:
30+
from_attributes = True
31+
32+
class Token(BaseModel):
33+
access_token: str
34+
token_type: str
35+
36+
class TokenData(BaseModel):
37+
email: Optional[str] = None

0 commit comments

Comments
 (0)