
- Set up project structure with FastAPI framework - Create database models for users, employees, departments, and job titles - Implement JWT authentication and authorization system - Set up SQLite database with SQLAlchemy ORM - Add Alembic migrations for database versioning - Create CRUD API endpoints for employee management - Implement category-based search functionality - Add OpenAPI documentation and health check endpoint - Update README with comprehensive setup and usage instructions
275 lines
8.5 KiB
Python
275 lines
8.5 KiB
Python
from typing import Any, List, Optional
|
|
|
|
from fastapi import APIRouter, Depends, HTTPException, Query
|
|
from sqlalchemy.orm import Session
|
|
|
|
from app import crud, models, schemas
|
|
from app.api import deps
|
|
|
|
router = APIRouter()
|
|
|
|
|
|
@router.get("/", response_model=List[schemas.Employee])
|
|
def read_employees(
|
|
db: Session = Depends(deps.get_db),
|
|
skip: int = 0,
|
|
limit: int = 100,
|
|
current_user: models.User = Depends(deps.get_current_active_user),
|
|
) -> Any:
|
|
"""
|
|
Retrieve employees.
|
|
"""
|
|
employees = crud.employee.get_all(db, skip=skip, limit=limit)
|
|
return employees
|
|
|
|
|
|
@router.post("/", response_model=schemas.Employee)
|
|
def create_employee(
|
|
*,
|
|
db: Session = Depends(deps.get_db),
|
|
employee_in: schemas.EmployeeCreate,
|
|
current_user: models.User = Depends(deps.get_current_active_user),
|
|
) -> Any:
|
|
"""
|
|
Create new employee.
|
|
"""
|
|
# Check if email already exists
|
|
employee = crud.employee.get_by_email(db, email=employee_in.email)
|
|
if employee:
|
|
raise HTTPException(
|
|
status_code=400,
|
|
detail="The employee with this email already exists in the system",
|
|
)
|
|
|
|
# Check if department exists
|
|
department = crud.department.get(db, id=employee_in.department_id)
|
|
if not department:
|
|
raise HTTPException(
|
|
status_code=404,
|
|
detail=f"Department with id {employee_in.department_id} not found",
|
|
)
|
|
|
|
# Check if job title exists
|
|
job_title = crud.job_title.get(db, id=employee_in.job_title_id)
|
|
if not job_title:
|
|
raise HTTPException(
|
|
status_code=404,
|
|
detail=f"Job title with id {employee_in.job_title_id} not found",
|
|
)
|
|
|
|
# Check if manager exists (if provided)
|
|
if employee_in.manager_id:
|
|
manager = crud.employee.get(db, id=employee_in.manager_id)
|
|
if not manager:
|
|
raise HTTPException(
|
|
status_code=404,
|
|
detail=f"Manager with id {employee_in.manager_id} not found",
|
|
)
|
|
|
|
employee = crud.employee.create(db, obj_in=employee_in)
|
|
return employee
|
|
|
|
|
|
@router.get("/{employee_id}", response_model=schemas.EmployeeWithDetails)
|
|
def read_employee(
|
|
*,
|
|
db: Session = Depends(deps.get_db),
|
|
employee_id: str,
|
|
current_user: models.User = Depends(deps.get_current_active_user),
|
|
) -> Any:
|
|
"""
|
|
Get employee by ID.
|
|
"""
|
|
employee = crud.employee.get(db, id=employee_id)
|
|
if not employee:
|
|
raise HTTPException(status_code=404, detail="Employee not found")
|
|
return employee
|
|
|
|
|
|
@router.put("/{employee_id}", response_model=schemas.Employee)
|
|
def update_employee(
|
|
*,
|
|
db: Session = Depends(deps.get_db),
|
|
employee_id: str,
|
|
employee_in: schemas.EmployeeUpdate,
|
|
current_user: models.User = Depends(deps.get_current_active_user),
|
|
) -> Any:
|
|
"""
|
|
Update an employee.
|
|
"""
|
|
employee = crud.employee.get(db, id=employee_id)
|
|
if not employee:
|
|
raise HTTPException(status_code=404, detail="Employee not found")
|
|
|
|
# If email is being updated, check if it already exists
|
|
if employee_in.email and employee_in.email != employee.email:
|
|
existing_employee = crud.employee.get_by_email(db, email=employee_in.email)
|
|
if existing_employee:
|
|
raise HTTPException(
|
|
status_code=400,
|
|
detail="The employee with this email already exists in the system",
|
|
)
|
|
|
|
# Check if department exists (if provided)
|
|
if employee_in.department_id:
|
|
department = crud.department.get(db, id=employee_in.department_id)
|
|
if not department:
|
|
raise HTTPException(
|
|
status_code=404,
|
|
detail=f"Department with id {employee_in.department_id} not found",
|
|
)
|
|
|
|
# Check if job title exists (if provided)
|
|
if employee_in.job_title_id:
|
|
job_title = crud.job_title.get(db, id=employee_in.job_title_id)
|
|
if not job_title:
|
|
raise HTTPException(
|
|
status_code=404,
|
|
detail=f"Job title with id {employee_in.job_title_id} not found",
|
|
)
|
|
|
|
# Check if manager exists (if provided)
|
|
if employee_in.manager_id:
|
|
# Prevent self-assignment as manager
|
|
if employee_in.manager_id == employee_id:
|
|
raise HTTPException(
|
|
status_code=400,
|
|
detail="An employee cannot be their own manager",
|
|
)
|
|
|
|
manager = crud.employee.get(db, id=employee_in.manager_id)
|
|
if not manager:
|
|
raise HTTPException(
|
|
status_code=404,
|
|
detail=f"Manager with id {employee_in.manager_id} not found",
|
|
)
|
|
|
|
employee = crud.employee.update(db, db_obj=employee, obj_in=employee_in)
|
|
return employee
|
|
|
|
|
|
@router.delete("/{employee_id}", status_code=204, response_model=None)
|
|
def delete_employee(
|
|
*,
|
|
db: Session = Depends(deps.get_db),
|
|
employee_id: str,
|
|
current_user: models.User = Depends(deps.get_current_active_superuser),
|
|
) -> Any:
|
|
"""
|
|
Delete an employee.
|
|
"""
|
|
employee = crud.employee.get(db, id=employee_id)
|
|
if not employee:
|
|
raise HTTPException(status_code=404, detail="Employee not found")
|
|
|
|
# Check if this employee is a manager for other employees
|
|
subordinates = db.query(models.Employee).filter(models.Employee.manager_id == employee_id).first()
|
|
if subordinates:
|
|
raise HTTPException(
|
|
status_code=400,
|
|
detail="Cannot delete employee who is a manager. Reassign subordinates first.",
|
|
)
|
|
|
|
crud.employee.remove(db, id=employee_id)
|
|
return None
|
|
|
|
|
|
@router.get("/department/{department_id}", response_model=List[schemas.Employee])
|
|
def read_employees_by_department(
|
|
*,
|
|
db: Session = Depends(deps.get_db),
|
|
department_id: str,
|
|
skip: int = 0,
|
|
limit: int = 100,
|
|
current_user: models.User = Depends(deps.get_current_active_user),
|
|
) -> Any:
|
|
"""
|
|
Retrieve employees by department.
|
|
"""
|
|
# Check if department exists
|
|
department = crud.department.get(db, id=department_id)
|
|
if not department:
|
|
raise HTTPException(status_code=404, detail="Department not found")
|
|
|
|
employees = crud.employee.get_by_department(
|
|
db, department_id=department_id, skip=skip, limit=limit
|
|
)
|
|
return employees
|
|
|
|
|
|
@router.get("/job-title/{job_title_id}", response_model=List[schemas.Employee])
|
|
def read_employees_by_job_title(
|
|
*,
|
|
db: Session = Depends(deps.get_db),
|
|
job_title_id: str,
|
|
skip: int = 0,
|
|
limit: int = 100,
|
|
current_user: models.User = Depends(deps.get_current_active_user),
|
|
) -> Any:
|
|
"""
|
|
Retrieve employees by job title.
|
|
"""
|
|
# Check if job title exists
|
|
job_title = crud.job_title.get(db, id=job_title_id)
|
|
if not job_title:
|
|
raise HTTPException(status_code=404, detail="Job title not found")
|
|
|
|
employees = crud.employee.get_by_job_title(
|
|
db, job_title_id=job_title_id, skip=skip, limit=limit
|
|
)
|
|
return employees
|
|
|
|
|
|
@router.get("/manager/{manager_id}", response_model=List[schemas.Employee])
|
|
def read_employees_by_manager(
|
|
*,
|
|
db: Session = Depends(deps.get_db),
|
|
manager_id: str,
|
|
skip: int = 0,
|
|
limit: int = 100,
|
|
current_user: models.User = Depends(deps.get_current_active_user),
|
|
) -> Any:
|
|
"""
|
|
Retrieve employees by manager.
|
|
"""
|
|
# Check if manager exists
|
|
manager = crud.employee.get(db, id=manager_id)
|
|
if not manager:
|
|
raise HTTPException(status_code=404, detail="Manager not found")
|
|
|
|
employees = crud.employee.get_by_manager(
|
|
db, manager_id=manager_id, skip=skip, limit=limit
|
|
)
|
|
return employees
|
|
|
|
|
|
@router.get("/search/", response_model=List[schemas.Employee])
|
|
def search_employees(
|
|
*,
|
|
db: Session = Depends(deps.get_db),
|
|
department_id: Optional[str] = None,
|
|
job_title_id: Optional[str] = None,
|
|
name: Optional[str] = None,
|
|
skills: Optional[List[str]] = Query(None),
|
|
categories: Optional[List[str]] = Query(None),
|
|
is_active: Optional[bool] = True,
|
|
skip: int = 0,
|
|
limit: int = 100,
|
|
current_user: models.User = Depends(deps.get_current_active_user),
|
|
) -> Any:
|
|
"""
|
|
Search employees by various criteria including categories and skills.
|
|
"""
|
|
search_params = schemas.EmployeeSearchParams(
|
|
department_id=department_id,
|
|
job_title_id=job_title_id,
|
|
name=name,
|
|
skills=skills,
|
|
categories=categories,
|
|
is_active=is_active,
|
|
)
|
|
|
|
employees = crud.employee.search(
|
|
db, params=search_params, skip=skip, limit=limit
|
|
)
|
|
return employees |