2025-12-10 12:02:17 +08:00

104 lines
3.7 KiB
Python

from collections import defaultdict
from typing import List
from fastapi import HTTPException, status
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from backend.modules.audit.models import AuditAction, AuditLog, AuditResourceType
from backend.modules.aws_accounts.models import AWSCredential, CustomerCredential
from backend.modules.customers.models import Customer
from backend.modules.users.models import User
async def list_customers(session: AsyncSession) -> List[Customer]:
customers = (await session.scalars(select(Customer))).all()
if not customers:
return customers
customer_ids = [c.id for c in customers]
cred_map: dict[int, list[str]] = defaultdict(list)
cred_rows = await session.execute(
select(CustomerCredential.customer_id, AWSCredential.name, AWSCredential.account_id)
.join(AWSCredential, AWSCredential.id == CustomerCredential.credential_id)
.where(CustomerCredential.customer_id.in_(customer_ids))
.where(CustomerCredential.is_allowed == 1)
)
for customer_id, cred_name, account_id in cred_rows:
cred_map[customer_id].append(f"{cred_name} ({account_id})")
user_map: dict[int, list[str]] = defaultdict(list)
user_rows = await session.execute(
select(User.customer_id, User.username).where(User.customer_id.in_(customer_ids))
)
for customer_id, username in user_rows:
user_map[customer_id].append(username)
for customer in customers:
# attach additional presentation fields for API response
setattr(customer, "credential_names", cred_map.get(customer.id, []))
setattr(customer, "usernames", user_map.get(customer.id, []))
return customers
async def create_customer(session: AsyncSession, data: dict, actor: User) -> Customer:
customer = Customer(**data)
session.add(customer)
await session.commit()
await session.refresh(customer)
session.add(
AuditLog(
user_id=actor.id,
customer_id=None,
action=AuditAction.CUSTOMER_CREATE,
resource_type=AuditResourceType.CUSTOMER,
resource_id=customer.id,
description=f"Create customer {customer.name}",
)
)
await session.commit()
return customer
async def update_customer(session: AsyncSession, customer_id: int, data: dict, actor: User) -> Customer:
customer = await session.get(Customer, customer_id)
if not customer:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Customer not found")
for field, value in data.items():
setattr(customer, field, value)
await session.commit()
await session.refresh(customer)
session.add(
AuditLog(
user_id=actor.id,
customer_id=customer.id,
action=AuditAction.CUSTOMER_UPDATE,
resource_type=AuditResourceType.CUSTOMER,
resource_id=customer.id,
description=f"Update customer {customer.name}",
payload=data,
)
)
await session.commit()
return customer
async def delete_customer(session: AsyncSession, customer_id: int, actor: User) -> None:
customer = await session.get(Customer, customer_id)
if not customer:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Customer not found")
await session.delete(customer)
session.add(
AuditLog(
user_id=actor.id,
customer_id=customer.id,
action=AuditAction.CUSTOMER_DELETE,
resource_type=AuditResourceType.CUSTOMER,
resource_id=customer.id,
description=f"Delete customer {customer.name}",
)
)
await session.commit()