"""Customer-card opt-in; global configuration remains the master switch.""" from fastapi import APIRouter, Depends, HTTPException from pydantic import BaseModel, Field, field_validator from app.core.auth_dependencies import get_current_user, require_permission from app.core.auth_service import AuthService from app.core.config import settings from .service import transaction router=APIRouter(prefix='/workflows/customers') async def read_access(user=Depends(get_current_user)): if not user.get('is_superadmin') and not any(AuthService.user_has_permission(user['id'],permission) for permission in ('customers.view','workflows.view')): raise HTTPException(403,'Du mangler rettighed til at se kunden eller workflows') return user def can_manage(user): return bool(user.get('is_superadmin') or all(AuthService.user_has_permission(user['id'],permission) for permission in ('customers.edit','workflows.activate'))) def activation_status(customer_id,cursor,user,lock=False): cursor.execute('SELECT id FROM customers WHERE id=%s'+(' FOR UPDATE' if lock else ''),(customer_id,)) if not cursor.fetchone(): raise HTTPException(404,'Kunden findes ikke') cursor.execute("SELECT to_regclass('public.bmc_workflow_customer_activation') AS name") present=cursor.fetchone() row=None if present and present.get('name'): cursor.execute('SELECT * FROM bmc_workflow_customer_activation WHERE customer_id=%s'+(' FOR UPDATE' if lock else ''),(customer_id,)) row=cursor.fetchone() inherited_enabled=customer_id in settings.WORKFLOWS_CUSTOMER_IDS enabled=bool(row['enabled']) if row else inherited_enabled return {'customer_id':customer_id,'enabled':enabled,'explicit_override':bool(row['enabled']) if row else None, 'inherited':row is None,'effective_enabled':bool(settings.WORKFLOWS_ENABLED and settings.WORKFLOWS_MODE=='active' and enabled), 'global_enabled':settings.WORKFLOWS_ENABLED,'mode':settings.WORKFLOWS_MODE, 'can_manage':can_manage(user),'can_view':True, 'updated_at':row.get('updated_at') if row else None,'updated_by':row.get('updated_by') if row else None, 'schema_ready':bool(present and present.get('name'))} class ActivationUpdate(BaseModel): enabled:bool reason:str=Field(min_length=3,max_length=1000) @field_validator('reason') @classmethod def reason_is_meaningful(cls,value): value=value.strip() if len(value)<3: raise ValueError('Begrundelsen skal være mindst tre tegn') return value @router.get('/{customer_id}/activation') def get_activation(customer_id:int,user=Depends(read_access)): with transaction() as cursor: return activation_status(customer_id,cursor,user) @router.put('/{customer_id}/activation') def set_activation(customer_id:int,payload:ActivationUpdate,user=Depends(require_permission('customers.edit')),workflow_access=Depends(require_permission('workflows.activate'))): with transaction() as cursor: # Parent-row locking serializes first-ever overrides and their audit records. previous=activation_status(customer_id,cursor,user,lock=True) if not previous['schema_ready']: raise HTTPException(503,'Kundeaktivering kræver workflowmigration 1067') cursor.execute('INSERT INTO bmc_workflow_customer_activation(customer_id,enabled,updated_by) VALUES(%s,%s,%s) ON CONFLICT(customer_id) DO UPDATE SET enabled=EXCLUDED.enabled,updated_by=EXCLUDED.updated_by,updated_at=now()', (customer_id,payload.enabled,user['id'])) cursor.execute('INSERT INTO bmc_workflow_customer_activation_history(customer_id,before_enabled,after_enabled,inherited_enabled,actor_id,reason) VALUES(%s,%s,%s,%s,%s,%s)', (customer_id,previous['explicit_override'],payload.enabled,customer_id in settings.WORKFLOWS_CUSTOMER_IDS,user['id'],payload.reason)) return activation_status(customer_id,cursor,user)