feat(customers): add initial admin bootstrap and csv import
This commit is contained in:
parent
c816e9869d
commit
ecab0fe6b6
27 changed files with 1197 additions and 34 deletions
|
|
@ -1,10 +1,10 @@
|
|||
import logging
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Response, status
|
||||
from fastapi import APIRouter, Depends, File, Form, HTTPException, Response, UploadFile, status
|
||||
from sqlalchemy.orm import Session
|
||||
from starlette.requests import Request
|
||||
|
||||
from app.core.rbac import require_permission
|
||||
from app.core.rbac import get_current_active_user, get_user_permission_names, require_permission
|
||||
from app.db.database import get_db
|
||||
from app.models.customer import Customer, CustomerContact
|
||||
from app.models.user import User
|
||||
|
|
@ -17,7 +17,13 @@ from app.schemas.customer import (
|
|||
CustomerResponse,
|
||||
CustomerUpdate,
|
||||
)
|
||||
from app.schemas.customer_import import (
|
||||
CustomerImportCommitResponse,
|
||||
CustomerImportPreviewResponse,
|
||||
ImportMode,
|
||||
)
|
||||
from app.services.audit_service import sanitize, write_audit_log
|
||||
from app.services.customer_import_service import CustomerImportService
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
|
@ -26,6 +32,23 @@ router = APIRouter(
|
|||
tags=["Customers"],
|
||||
)
|
||||
|
||||
MAX_IMPORT_SIZE_BYTES = 5 * 1024 * 1024
|
||||
|
||||
|
||||
async def read_import_file(file: UploadFile) -> bytes:
|
||||
content = await file.read(MAX_IMPORT_SIZE_BYTES + 1)
|
||||
if len(content) > MAX_IMPORT_SIZE_BYTES:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_413_REQUEST_ENTITY_TOO_LARGE,
|
||||
detail="CSV-Datei darf maximal 5 MB groß sein",
|
||||
)
|
||||
if not content:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail="CSV-Datei ist leer",
|
||||
)
|
||||
return content
|
||||
|
||||
|
||||
def get_customer_or_404(db: Session, customer_id: int) -> Customer:
|
||||
customer = CustomerRepository.get_by_id(db, customer_id)
|
||||
|
|
@ -116,6 +139,44 @@ def create_customer(
|
|||
return created_customer
|
||||
|
||||
|
||||
@router.post("/import/preview", response_model=CustomerImportPreviewResponse)
|
||||
async def preview_customer_import(
|
||||
mode: ImportMode = Form(...),
|
||||
file: UploadFile = File(...),
|
||||
db: Session = Depends(get_db),
|
||||
current_user: User = Depends(require_permission("customers.read")),
|
||||
):
|
||||
logger.info("customers.import.preview", extra={"actor_user_id": current_user.id, "mode": mode})
|
||||
content = await read_import_file(file)
|
||||
try:
|
||||
return CustomerImportService.preview(db, content, mode)
|
||||
except ValueError as exc:
|
||||
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(exc)) from exc
|
||||
|
||||
|
||||
@router.post("/import/commit", response_model=CustomerImportCommitResponse)
|
||||
async def commit_customer_import(
|
||||
request: Request,
|
||||
mode: ImportMode = Form(...),
|
||||
file: UploadFile = File(...),
|
||||
db: Session = Depends(get_db),
|
||||
current_user: User = Depends(get_current_active_user),
|
||||
):
|
||||
permissions = get_user_permission_names(current_user)
|
||||
required_permissions = {"customers.create"} if mode == "create_only" else {"customers.update"}
|
||||
if mode == "upsert":
|
||||
required_permissions = {"customers.create", "customers.update"}
|
||||
if not required_permissions.issubset(permissions):
|
||||
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Keine Berechtigung")
|
||||
|
||||
logger.info("customers.import.commit", extra={"actor_user_id": current_user.id, "mode": mode})
|
||||
content = await read_import_file(file)
|
||||
try:
|
||||
return CustomerImportService.commit(db, content, mode, actor=current_user, request=request)
|
||||
except ValueError as exc:
|
||||
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(exc)) from exc
|
||||
|
||||
|
||||
@router.put("/{customer_id}", response_model=CustomerResponse)
|
||||
def update_customer(
|
||||
customer_id: int,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue