"""Explicit case access lists supplement the existing general case permissions.""" from fastapi import APIRouter,Depends,HTTPException from pydantic import BaseModel,Field from app.core.auth_dependencies import get_current_user from app.core.case_visibility import require_case from app.core.database import atomic_transaction,execute_query,execute_query_single from app.modules.planner.backend.work import audit router=APIRouter() def can_manage(user): return bool(user.get('is_superadmin') or 'cases.manage_confidential' in set(user.get('permissions') or [])) def require_read(user,sag_id): if not (user.get('is_superadmin') or set(user.get('permissions') or []) & {'cases.view','tickets.view'}): raise HTTPException(403,'Du har ikke adgang til sager') require_case(user,sag_id) if not execute_query_single('SELECT id FROM sag_sager WHERE id=%s AND deleted_at IS NULL',(sag_id,)): raise HTTPException(404,'Sagen findes ikke') def state(sag_id): row=execute_query_single('SELECT version,restricted FROM sag_case_visibility WHERE sag_id=%s',(sag_id,)) return {'restricted':row['restricted'] if row else False,'version':row['version'] if row else 0, 'user_ids':[r['user_id'] for r in execute_query('SELECT user_id FROM sag_case_visibility_users WHERE sag_id=%s',(sag_id,)) or []], 'group_ids':[r['group_id'] for r in execute_query('SELECT group_id FROM sag_case_visibility_groups WHERE sag_id=%s',(sag_id,)) or []]} @router.get('/sag/{sag_id}/visibility') def get_visibility(sag_id:int,user:dict=Depends(get_current_user)): require_read(user,sag_id) result=state(sag_id) result['can_manage']=can_manage(user) if result['can_manage']: result['users']=execute_query('SELECT user_id AS id,COALESCE(full_name,username) AS name FROM users WHERE is_active ORDER BY name') or [] result['groups']=execute_query('SELECT id,name FROM groups ORDER BY name') or [] else: result.pop('user_ids') result.pop('group_ids') return result class VisibilityInput(BaseModel): restricted:bool version:int=Field(ge=0) user_ids:list[int]=Field(default_factory=list,max_length=1000) group_ids:list[int]=Field(default_factory=list,max_length=1000) @router.put('/sag/{sag_id}/visibility') def update_visibility(sag_id:int,payload:VisibilityInput,user:dict=Depends(get_current_user)): require_read(user,sag_id) if not can_manage(user): raise HTTPException(403,'Du må ikke ændre fortrolighed') ids,groups=sorted(set(payload.user_ids)),sorted(set(payload.group_ids)) if payload.restricted and not ids and not groups: raise HTTPException(400,'Vælg mindst én medarbejder eller gruppe') if payload.restricted and not user.get('is_superadmin') and user['id'] not in ids: own_groups=execute_query('SELECT group_id FROM user_groups WHERE user_id=%s AND group_id=ANY(%s)',(user['id'],groups)) or [] if not own_groups: raise HTTPException(400,'Du skal bevare din egen adgang til sagen') with atomic_transaction(): execute_query('SELECT id FROM sag_sager WHERE id=%s FOR UPDATE',(sag_id,)) old=state(sag_id) if old['version']!=payload.version: raise HTTPException(409,'Adgangen er ændret. Genindlæs.') if len(execute_query('SELECT user_id FROM users WHERE user_id=ANY(%s) AND is_active',(ids,)) or [])!=len(ids): raise HTTPException(400,'Ukendt eller inaktiv medarbejder') if len(execute_query('SELECT id FROM groups WHERE id=ANY(%s)',(groups,)) or [])!=len(groups): raise HTTPException(400,'Ukendt gruppe') execute_query('''INSERT INTO sag_case_visibility(sag_id,updated_by,restricted) VALUES(%s,%s,%s) ON CONFLICT(sag_id) DO UPDATE SET version=sag_case_visibility.version+1,restricted=EXCLUDED.restricted, updated_by=EXCLUDED.updated_by,updated_at=NOW()''',(sag_id,user['id'],payload.restricted),fetch=False) execute_query('DELETE FROM sag_case_visibility_users WHERE sag_id=%s',(sag_id,),fetch=False) execute_query('DELETE FROM sag_case_visibility_groups WHERE sag_id=%s',(sag_id,),fetch=False) if payload.restricted: for uid in ids: execute_query('INSERT INTO sag_case_visibility_users(sag_id,user_id) VALUES(%s,%s)',(sag_id,uid),fetch=False) for gid in groups: execute_query('INSERT INTO sag_case_visibility_groups(sag_id,group_id) VALUES(%s,%s)',(sag_id,gid),fetch=False) new=state(sag_id) audit(user,'visibility_update','case',sag_id,old,new,sag_id) return new