Adding OData Import
This commit is contained in:
1 parent
c8696e67b5
commit
291416544e
18 files changed
+547
-3
No files matched your search
@@ -0,0 +1,120 @@
|
||||
from fastapi import APIRouter, Depends, HTTPException, status
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.core.database import get_db
|
||||
from app.crud import audit as audit_crud
|
||||
from app.crud import imported_part as imported_part_crud
|
||||
from app.crud import imported_part_config as config_crud
|
||||
from app.deps import require_permission
|
||||
from app.models.user import User
|
||||
from app.schemas.imported_part import (
|
||||
ImportedPartConfigRead,
|
||||
ImportedPartConfigUpdate,
|
||||
ImportedPartRead,
|
||||
SyncResult,
|
||||
)
|
||||
from app.services import odata as odata_service
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@router.get("", response_model=list[ImportedPartRead])
|
||||
async def list_imported_parts(
|
||||
skip: int = 0,
|
||||
limit: int = 500,
|
||||
db: AsyncSession = Depends(get_db),
|
||||
_: User = Depends(require_permission("imported_parts:read")),
|
||||
):
|
||||
return await imported_part_crud.list_all(db, skip=skip, limit=limit)
|
||||
|
||||
|
||||
@router.get("/config", response_model=ImportedPartConfigRead)
|
||||
async def get_config(
|
||||
db: AsyncSession = Depends(get_db),
|
||||
_: User = Depends(require_permission("imported_parts:write")),
|
||||
):
|
||||
config = await config_crud.get(db)
|
||||
if config is None:
|
||||
return ImportedPartConfigRead(odata_url=None, username=None, has_password=False)
|
||||
return ImportedPartConfigRead(
|
||||
odata_url=config.odata_url,
|
||||
username=config.username,
|
||||
has_password=bool(config.password),
|
||||
)
|
||||
|
||||
|
||||
@router.patch("/config", response_model=ImportedPartConfigRead)
|
||||
async def update_config(
|
||||
payload: ImportedPartConfigUpdate,
|
||||
db: AsyncSession = Depends(get_db),
|
||||
actor: User = Depends(require_permission("imported_parts:write")),
|
||||
):
|
||||
current = await config_crud.get(db)
|
||||
# Keep existing password if not provided in the update
|
||||
new_password = payload.password if payload.password is not None else (current.password if current else None)
|
||||
config = await config_crud.upsert(
|
||||
db,
|
||||
odata_url=payload.odata_url,
|
||||
username=payload.username,
|
||||
password=new_password,
|
||||
)
|
||||
await audit_crud.log(
|
||||
db, actor=actor, action="update", resource_type="ImportedPartConfig",
|
||||
resource_id=1,
|
||||
description="Updated ImportedPart OData configuration",
|
||||
)
|
||||
return ImportedPartConfigRead(
|
||||
odata_url=config.odata_url,
|
||||
username=config.username,
|
||||
has_password=bool(config.password),
|
||||
)
|
||||
|
||||
|
||||
@router.post("/refresh", response_model=SyncResult)
|
||||
async def refresh_imported_parts(
|
||||
db: AsyncSession = Depends(get_db),
|
||||
actor: User = Depends(require_permission("imported_parts:write")),
|
||||
):
|
||||
config = await config_crud.get(db)
|
||||
if not config or not config.odata_url:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
||||
detail="OData URL is not configured.",
|
||||
)
|
||||
records = await odata_service.fetch(config.odata_url, config.username, config.password)
|
||||
created, updated = await imported_part_crud.upsert_bulk(db, records)
|
||||
await audit_crud.log(
|
||||
db, actor=actor, action="update", resource_type="ImportedPart",
|
||||
resource_id=None,
|
||||
description=f"OData sync: {created} created, {updated} updated ({len(records)} total records)",
|
||||
)
|
||||
return SyncResult(created=created, updated=updated, total=len(records))
|
||||
|
||||
|
||||
@router.get("/{inventory_id}", response_model=ImportedPartRead)
|
||||
async def get_imported_part(
|
||||
inventory_id: str,
|
||||
db: AsyncSession = Depends(get_db),
|
||||
_: User = Depends(require_permission("imported_parts:read")),
|
||||
):
|
||||
part = await imported_part_crud.get(db, inventory_id)
|
||||
if part is None:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Imported part not found")
|
||||
return part
|
||||
|
||||
|
||||
@router.delete("/{inventory_id}", status_code=status.HTTP_204_NO_CONTENT)
|
||||
async def delete_imported_part(
|
||||
inventory_id: str,
|
||||
db: AsyncSession = Depends(get_db),
|
||||
actor: User = Depends(require_permission("imported_parts:delete")),
|
||||
):
|
||||
part = await imported_part_crud.get(db, inventory_id)
|
||||
if part is None:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Imported part not found")
|
||||
await imported_part_crud.delete(db, part)
|
||||
await audit_crud.log(
|
||||
db, actor=actor, action="delete", resource_type="ImportedPart",
|
||||
resource_id=None,
|
||||
description=audit_crud.describe_delete("ImportedPart", 0, inventory_id),
|
||||
)
|
||||
+2
-1
@@ -1,6 +1,6 @@
|
||||
from fastapi import APIRouter
|
||||
|
||||
from app.api import audit_log, auth, iso_threads, manufacturers, part_types, roles, scope_models, sub_part_types, unc_threads, users
|
||||
from app.api import audit_log, auth, imported_parts, iso_threads, manufacturers, part_types, roles, scope_models, sub_part_types, unc_threads, users
|
||||
|
||||
api_router = APIRouter()
|
||||
api_router.include_router(auth.router, prefix="/auth", tags=["auth"])
|
||||
@@ -12,4 +12,5 @@ api_router.include_router(manufacturers.router, prefix="/manufacturers", tags=["
|
||||
api_router.include_router(scope_models.router, prefix="/scope-models", tags=["scope-models"])
|
||||
api_router.include_router(part_types.router, prefix="/part-types", tags=["part-types"])
|
||||
api_router.include_router(sub_part_types.router, prefix="/sub-part-types", tags=["sub-part-types"])
|
||||
api_router.include_router(imported_parts.router, prefix="/imported-parts", tags=["imported-parts"])
|
||||
api_router.include_router(audit_log.router, prefix="/audit-log", tags=["audit-log"])
|
||||
Reference in new issue
Block a user