62 lines
3.9 KiB
Python
62 lines
3.9 KiB
Python
"""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)
|