first commit
This commit is contained in:
commit
6e354ba041
109 changed files with 12110 additions and 0 deletions
116
backend/app/routers/auth.py
Normal file
116
backend/app/routers/auth.py
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
from datetime import timedelta
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, status
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.config import settings
|
||||
from app.database import get_db
|
||||
from app.dependencies import (
|
||||
generate_reset_token,
|
||||
get_current_user,
|
||||
reset_token_expiry,
|
||||
)
|
||||
from app.models.user import User
|
||||
from app.schemas.user import (
|
||||
ForgotPasswordRequest,
|
||||
LoginRequest,
|
||||
MessageResponse,
|
||||
ResetPasswordRequest,
|
||||
TokenResponse,
|
||||
UserCreate,
|
||||
UserResponse,
|
||||
UserUpdate,
|
||||
)
|
||||
from app.services.user_service import (
|
||||
authenticate_user,
|
||||
create_password_reset_token,
|
||||
create_user,
|
||||
get_user_by_email,
|
||||
get_user_by_username,
|
||||
get_valid_reset_token,
|
||||
update_user,
|
||||
)
|
||||
from app.utils.security import create_access_token, create_refresh_token, hash_password
|
||||
|
||||
router = APIRouter(prefix="/auth", tags=["auth"])
|
||||
|
||||
|
||||
@router.post("/register", response_model=UserResponse, status_code=status.HTTP_201_CREATED)
|
||||
def register(data: UserCreate, db: Session = Depends(get_db)) -> User:
|
||||
if get_user_by_email(db, data.email.lower()):
|
||||
raise HTTPException(status_code=status.HTTP_409_CONFLICT, detail="Email already registered")
|
||||
|
||||
if get_user_by_username(db, data.username.lower()):
|
||||
raise HTTPException(status_code=status.HTTP_409_CONFLICT, detail="Username already taken")
|
||||
|
||||
return create_user(db, data)
|
||||
|
||||
|
||||
@router.post("/login", response_model=TokenResponse)
|
||||
def login(data: LoginRequest, db: Session = Depends(get_db)) -> TokenResponse:
|
||||
user = authenticate_user(db, data.username_or_email, data.password)
|
||||
if user is None:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||
detail="Invalid username/email or password",
|
||||
)
|
||||
|
||||
if not user.is_active:
|
||||
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Account is inactive")
|
||||
|
||||
access_token = create_access_token(
|
||||
user.email,
|
||||
timedelta(days=7) if data.remember_me else None,
|
||||
)
|
||||
|
||||
return TokenResponse(
|
||||
access_token=access_token,
|
||||
refresh_token=create_refresh_token(user.email),
|
||||
user=UserResponse.model_validate(user),
|
||||
)
|
||||
|
||||
|
||||
@router.get("/me", response_model=UserResponse)
|
||||
def get_me(current_user: User = Depends(get_current_user)) -> User:
|
||||
return current_user
|
||||
|
||||
|
||||
@router.patch("/me", response_model=UserResponse)
|
||||
def update_me(
|
||||
data: UserUpdate,
|
||||
current_user: User = Depends(get_current_user),
|
||||
db: Session = Depends(get_db),
|
||||
) -> User:
|
||||
return update_user(db, current_user, data)
|
||||
|
||||
|
||||
@router.post("/forgot-password", response_model=MessageResponse)
|
||||
def forgot_password(data: ForgotPasswordRequest, db: Session = Depends(get_db)) -> MessageResponse:
|
||||
user = get_user_by_email(db, data.email.lower())
|
||||
if user is None:
|
||||
return MessageResponse(message="If that email exists, a reset link has been sent.")
|
||||
|
||||
token = generate_reset_token()
|
||||
create_password_reset_token(db, user, token, reset_token_expiry())
|
||||
|
||||
response = MessageResponse(message="If that email exists, a reset link has been sent.")
|
||||
if settings.debug:
|
||||
response.reset_token = token
|
||||
return response
|
||||
|
||||
|
||||
@router.post("/reset-password", response_model=MessageResponse)
|
||||
def reset_password(data: ResetPasswordRequest, db: Session = Depends(get_db)) -> MessageResponse:
|
||||
reset = get_valid_reset_token(db, data.token)
|
||||
if reset is None:
|
||||
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Invalid or expired reset token")
|
||||
|
||||
user = db.query(User).filter(User.id == reset.user_id).first()
|
||||
if user is None:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="User not found")
|
||||
|
||||
user.hashed_password = hash_password(data.new_password)
|
||||
reset.used = True
|
||||
db.commit()
|
||||
|
||||
return MessageResponse(message="Password reset successfully. You can now log in.")
|
||||
Loading…
Add table
Add a link
Reference in a new issue