This commit is contained in:
HotSwapp
2025-08-09 16:37:57 -05:00
parent 5f74243c8c
commit c2f3c4411d
35 changed files with 9209 additions and 4633 deletions

View File

@@ -20,7 +20,8 @@ from app.auth.schemas import (
Token,
UserCreate,
UserResponse,
LoginRequest
LoginRequest,
ThemePreferenceUpdate
)
from app.config import settings
@@ -116,4 +117,23 @@ async def list_users(
):
"""List all users (admin only)"""
users = db.query(User).all()
return users
return users
@router.post("/theme-preference")
async def update_theme_preference(
theme_data: ThemePreferenceUpdate,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user)
):
"""Update user's theme preference"""
if theme_data.theme_preference not in ['light', 'dark']:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="Theme preference must be 'light' or 'dark'"
)
current_user.theme_preference = theme_data.theme_preference
db.commit()
return {"message": "Theme preference updated successfully", "theme": theme_data.theme_preference}

View File

@@ -2,7 +2,7 @@
Document Management API endpoints - QDROs, Templates, and General Documents
"""
from typing import List, Optional, Dict, Any
from fastapi import APIRouter, Depends, HTTPException, status, Query, UploadFile, File
from fastapi import APIRouter, Depends, HTTPException, status, Query, UploadFile, File, Form
from sqlalchemy.orm import Session, joinedload
from sqlalchemy import or_, func, and_, desc, asc, text
from datetime import date, datetime
@@ -17,6 +17,7 @@ from app.models.rolodex import Rolodex
from app.models.lookups import FormIndex, FormList, Footer, Employee
from app.models.user import User
from app.auth.security import get_current_user
from app.models.additional import Document
router = APIRouter()
@@ -662,4 +663,105 @@ def _merge_template_variables(content: str, variables: Dict[str, Any]) -> str:
merged = merged.replace(f"{{{{{var_name}}}}}", str(value or ""))
merged = merged.replace(f"^{var_name}", str(value or ""))
return merged
return merged
@router.post("/upload/{file_no}")
async def upload_document(
file_no: str,
file: UploadFile = File(...),
description: Optional[str] = Form(None),
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user)
):
"""Upload a document to a file"""
file_obj = db.query(FileModel).filter(FileModel.file_no == file_no).first()
if not file_obj:
raise HTTPException(status_code=404, detail="File not found")
if not file.filename:
raise HTTPException(status_code=400, detail="No file uploaded")
allowed_types = [
"application/pdf",
"application/msword",
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
"image/jpeg",
"image/png"
]
if file.content_type not in allowed_types:
raise HTTPException(status_code=400, detail="Invalid file type")
max_size = 10 * 1024 * 1024 # 10MB
content = await file.read()
if len(content) > max_size:
raise HTTPException(status_code=400, detail="File too large")
upload_dir = f"uploads/{file_no}"
os.makedirs(upload_dir, exist_ok=True)
ext = file.filename.split(".")[-1]
unique_name = f"{uuid.uuid4()}.{ext}"
path = f"{upload_dir}/{unique_name}"
with open(path, "wb") as f:
f.write(content)
doc = Document(
file_no=file_no,
filename=file.filename,
path=path,
description=description,
type=file.content_type,
size=len(content),
uploaded_by=current_user.username
)
db.add(doc)
db.commit()
db.refresh(doc)
return doc
@router.get("/{file_no}/uploaded")
async def list_uploaded_documents(
file_no: str,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user)
):
"""List uploaded documents for a file"""
docs = db.query(Document).filter(Document.file_no == file_no).all()
return docs
@router.delete("/uploaded/{doc_id}")
async def delete_document(
doc_id: int,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user)
):
"""Delete an uploaded document"""
doc = db.query(Document).filter(Document.id == doc_id).first()
if not doc:
raise HTTPException(status_code=404, detail="Document not found")
if os.path.exists(doc.path):
os.remove(doc.path)
db.delete(doc)
db.commit()
return {"message": "Document deleted successfully"}
@router.put("/uploaded/{doc_id}")
async def update_document(
doc_id: int,
description: str = Form(...),
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user)
):
"""Update document description"""
doc = db.query(Document).filter(Document.id == doc_id).first()
if not doc:
raise HTTPException(status_code=404, detail="Document not found")
doc.description = description
db.commit()
db.refresh(doc)
return doc

37
app/api/settings.py Normal file
View File

@@ -0,0 +1,37 @@
"""
Public (authenticated) settings endpoints for client configuration
"""
from fastapi import APIRouter, Depends
from sqlalchemy.orm import Session
from app.database.base import get_db
from app.auth.security import get_current_user
from app.models.user import User
from app.models.lookups import SystemSetup
router = APIRouter()
@router.get("/inactivity_warning_minutes")
async def get_inactivity_warning_minutes(
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
):
"""Returns the inactivity warning threshold in minutes (default 240)."""
default_minutes = 240
setting = (
db.query(SystemSetup)
.filter(SystemSetup.setting_key == "inactivity_warning_minutes")
.first()
)
if not setting:
return {"minutes": default_minutes}
try:
minutes = int(setting.setting_value)
except Exception:
minutes = default_minutes
return {"minutes": minutes}