ifixkart-backend/Backend/app/api/v1/routers/UserCreationRouter.py

166 lines
5.9 KiB
Python

from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.orm import Session
from typing import List
from datetime import datetime, timezone
import ulid
from app.core.database.db_session import get_db
from app.repositories.user_repository import user_repository
from app.models.UserModel import User
from app.models.RoleModel import Role
from app.schemas.User import UserCreate, UserUpdate, UserResponse
from app.core.permissions.RoleChecker import RoleChecker, PermissionChecker
from app.core.validators.password_validator import validate_password_complexity
from app.utils.Hash_util import hash_password
from app.services.code_generator_service import code_generator_service
router = APIRouter(prefix="/api/v1/users", tags=["User Creation"])
@router.post("/create", response_model=UserResponse, status_code=status.HTTP_201_CREATED)
def create_user(
data: UserCreate,
db: Session = Depends(get_db),
current_user: User = Depends(PermissionChecker("user.create"))
):
# 1. Check duplicate identity parameters
duplicate = user_repository.check_duplicate_identity(db, data.email, data.phone)
if duplicate:
raise HTTPException(status_code=400, detail="User with this email or phone number already exists.")
# 2. Check Role existence and fetch prefix
role = db.get(Role, data.role_id)
if not role or role.deleted_at is not None:
raise HTTPException(status_code=400, detail="Specified role ID is invalid or inactive.")
# 3. Validate password complexity
validate_password_complexity(data.password)
# 4. Generate sequential employee code
prefix = role.role_prefix
employee_code = code_generator_service.generate_next_code(db, "User", prefix)
# 5. Build user record
user_id = str(ulid.ULID())
new_user = User(
user_id=user_id,
employee_code=employee_code,
first_name=data.first_name,
last_name=data.last_name,
display_name=data.display_name or f"{data.first_name} {data.last_name}",
email=data.email,
phone=data.phone,
password_hash=hash_password(data.password),
gender=data.gender,
dob=data.dob,
department_id=data.department_id,
designation_id=data.designation_id,
role_id=data.role_id,
manager_id=data.manager_id,
is_active=True
)
user_repository.create(db, new_user)
return new_user
@router.get("/all", response_model=List[UserResponse])
def get_all_users(
skip: int = 0,
limit: int = 100,
db: Session = Depends(get_db),
current_user: User = Depends(PermissionChecker("user.view"))
):
users = user_repository.get_active_users(db, skip, limit)
from app.models.AuditLogModel import AuditLog
for u in users:
latest = (
db.query(AuditLog)
.filter(AuditLog.user_id == u.user_id)
.order_by(AuditLog.created_at.desc())
.first()
)
if latest:
u.last_activity = f"{latest.action.replace('_', ' ').title()} {latest.entity_type}"
else:
u.last_activity = "No recent activity"
return users
@router.get("/profile/{user_id}", response_model=UserResponse)
def get_user_profile(
user_id: str,
db: Session = Depends(get_db),
current_user: User = Depends(PermissionChecker("user.view"))
):
user = user_repository.get_by_id(db, user_id)
if not user or user.deleted_at is not None:
raise HTTPException(status_code=404, detail="User not found")
return user
@router.put("/update/{user_id}", response_model=UserResponse)
def update_user_profile(
user_id: str,
payload: UserUpdate,
db: Session = Depends(get_db),
current_user: User = Depends(PermissionChecker("user.update"))
):
user = user_repository.get_by_id(db, user_id)
if not user or user.deleted_at is not None:
raise HTTPException(status_code=404, detail="User not found")
# Check email/phone uniqueness if being updated
if payload.email and payload.email != user.email:
if user_repository.get_by_email(db, payload.email):
raise HTTPException(status_code=400, detail="Email is already registered.")
user.email = payload.email
if payload.phone and payload.phone != user.phone:
if user_repository.get_by_phone(db, payload.phone):
raise HTTPException(status_code=400, detail="Phone number is already registered.")
user.phone = payload.phone
# Update strings
if payload.first_name:
user.first_name = payload.first_name
if payload.last_name:
user.last_name = payload.last_name
if payload.display_name:
user.display_name = payload.display_name
if payload.gender:
user.gender = payload.gender
if payload.dob:
user.dob = payload.dob
if payload.profile_image_id:
user.profile_image_id = payload.profile_image_id
# Update relationships
if payload.department_id:
user.department_id = payload.department_id
if payload.designation_id:
user.designation_id = payload.designation_id
if payload.role_id:
user.role_id = payload.role_id
if payload.manager_id:
user.manager_id = payload.manager_id
# If resetting password
if payload.password:
validate_password_complexity(payload.password)
user.password_hash = hash_password(payload.password)
user_repository.update(db, user)
return user
@router.delete("/delete/{user_id}")
def delete_user_profile(
user_id: str,
db: Session = Depends(get_db),
current_user: User = Depends(PermissionChecker("user.delete"))
):
user = user_repository.get_by_id(db, user_id)
if not user or user.deleted_at is not None:
raise HTTPException(status_code=404, detail="User not found")
# Safe soft delete
user.deleted_at = datetime.now(timezone.utc)
user.is_active = False
db.commit()
return {"detail": "User soft deleted successfully"}