mirror of
https://github.com/OHV-IT/collabrix.git
synced 2025-12-15 16:48:36 +01:00
- Complete chat application similar to Microsoft Teams - Code snippet library with syntax highlighting - Real-time messaging with WebSockets - File upload with Office integration - Department-based permissions - Dark/Light theme support - Production deployment with SSL/Reverse Proxy - Docker containerization - PostgreSQL database with SQLModel ORM
164 lines
5.5 KiB
Python
164 lines
5.5 KiB
Python
from fastapi import APIRouter, Depends, HTTPException, status, UploadFile, File
|
|
from sqlmodel import Session, select
|
|
from datetime import timedelta
|
|
import os
|
|
import uuid
|
|
from pathlib import Path
|
|
from app.database import get_session
|
|
from app.models import User
|
|
from app.schemas import UserCreate, UserResponse, UserLogin, Token
|
|
from app.auth import get_password_hash, authenticate_user, create_access_token, get_current_user
|
|
from app.config import get_settings
|
|
|
|
router = APIRouter(prefix="/auth", tags=["Authentication"])
|
|
settings = get_settings()
|
|
|
|
|
|
@router.post("/register", response_model=UserResponse, status_code=status.HTTP_201_CREATED)
|
|
def register(user_data: UserCreate, session: Session = Depends(get_session)):
|
|
"""Register a new user"""
|
|
# Check if username already exists
|
|
statement = select(User).where(User.username == user_data.username)
|
|
existing_user = session.exec(statement).first()
|
|
if existing_user:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_400_BAD_REQUEST,
|
|
detail="Username already registered"
|
|
)
|
|
|
|
# Check if email already exists
|
|
statement = select(User).where(User.email == user_data.email)
|
|
existing_email = session.exec(statement).first()
|
|
if existing_email:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_400_BAD_REQUEST,
|
|
detail="Email already registered"
|
|
)
|
|
|
|
# Create new user
|
|
hashed_password = get_password_hash(user_data.password)
|
|
new_user = User(
|
|
username=user_data.username,
|
|
email=user_data.email,
|
|
full_name=user_data.full_name,
|
|
hashed_password=hashed_password
|
|
)
|
|
|
|
session.add(new_user)
|
|
session.commit()
|
|
session.refresh(new_user)
|
|
|
|
return new_user
|
|
|
|
|
|
@router.post("/login", response_model=Token)
|
|
def login(login_data: UserLogin, session: Session = Depends(get_session)):
|
|
"""Login and get access token"""
|
|
user = authenticate_user(session, login_data.username, login_data.password)
|
|
|
|
if not user:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_401_UNAUTHORIZED,
|
|
detail="Incorrect username or password",
|
|
headers={"WWW-Authenticate": "Bearer"},
|
|
)
|
|
|
|
access_token_expires = timedelta(minutes=settings.access_token_expire_minutes)
|
|
access_token = create_access_token(
|
|
data={"sub": user.username}, expires_delta=access_token_expires
|
|
)
|
|
|
|
return {"access_token": access_token, "token_type": "bearer"}
|
|
|
|
|
|
@router.get("/me", response_model=UserResponse)
|
|
def get_current_user_info(current_user: User = Depends(get_current_user)):
|
|
"""Get current user information"""
|
|
return current_user
|
|
|
|
|
|
@router.put("/me", response_model=UserResponse)
|
|
def update_profile(
|
|
profile_data: dict,
|
|
current_user: User = Depends(get_current_user),
|
|
session: Session = Depends(get_session)
|
|
):
|
|
"""Update current user profile"""
|
|
# Check if email is being changed and if it already exists
|
|
if "email" in profile_data and profile_data["email"] != current_user.email:
|
|
statement = select(User).where(User.email == profile_data["email"])
|
|
existing_email = session.exec(statement).first()
|
|
if existing_email:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_400_BAD_REQUEST,
|
|
detail="Email already registered"
|
|
)
|
|
current_user.email = profile_data["email"]
|
|
|
|
# Update full_name if provided
|
|
if "full_name" in profile_data:
|
|
current_user.full_name = profile_data["full_name"]
|
|
|
|
# Update password if provided
|
|
if "password" in profile_data and profile_data["password"]:
|
|
current_user.hashed_password = get_password_hash(profile_data["password"])
|
|
|
|
# Update profile_picture if provided
|
|
if "profile_picture" in profile_data:
|
|
current_user.profile_picture = profile_data["profile_picture"]
|
|
|
|
# Update theme if provided
|
|
if "theme" in profile_data:
|
|
if profile_data["theme"] in ["light", "dark"]:
|
|
current_user.theme = profile_data["theme"]
|
|
|
|
session.add(current_user)
|
|
session.commit()
|
|
session.refresh(current_user)
|
|
|
|
return current_user
|
|
|
|
|
|
@router.post("/me/profile-picture", response_model=UserResponse)
|
|
async def upload_profile_picture(
|
|
file: UploadFile = File(...),
|
|
current_user: User = Depends(get_current_user),
|
|
session: Session = Depends(get_session)
|
|
):
|
|
"""Upload profile picture"""
|
|
# Validate file type
|
|
if not file.content_type or not file.content_type.startswith('image/'):
|
|
raise HTTPException(
|
|
status_code=status.HTTP_400_BAD_REQUEST,
|
|
detail="Only image files are allowed"
|
|
)
|
|
|
|
# Create uploads directory if it doesn't exist
|
|
upload_dir = Path("uploads/profile_pictures")
|
|
upload_dir.mkdir(parents=True, exist_ok=True)
|
|
|
|
# Generate unique filename
|
|
file_extension = os.path.splitext(file.filename)[1]
|
|
unique_filename = f"{uuid.uuid4()}{file_extension}"
|
|
file_path = upload_dir / unique_filename
|
|
|
|
# Save file
|
|
with open(file_path, "wb") as buffer:
|
|
content = await file.read()
|
|
buffer.write(content)
|
|
|
|
# Delete old profile picture if exists
|
|
if current_user.profile_picture:
|
|
old_file_path = Path(current_user.profile_picture)
|
|
if old_file_path.exists():
|
|
old_file_path.unlink()
|
|
|
|
# Update user profile picture path
|
|
current_user.profile_picture = str(file_path)
|
|
|
|
session.add(current_user)
|
|
session.commit()
|
|
session.refresh(current_user)
|
|
|
|
return current_user
|