# app_audit audit.dspy - 审计日志 API # 查看/备份/删除 仅 owner.audit 角色(审计独立性:superuser 也无权访问) # action: list / backup / delete user_id = await get_user() if not user_id: return json.dumps({'ok': False, 'error': '未登录'}, ensure_ascii=False) action = (params_kw or {}).get('action', 'list') from app_audit.audit_service import ( is_audit_role, list_audit_logs, backup_audit_logs, delete_audit_logs, ) # 查 username 和 client_ip username = user_id try: async with get_sor_context(request._run_ns, 'pipeline') as _sor: _u = await _sor.sqlExe("SELECT username FROM users WHERE id=${u}$", {'u': user_id}) if _u: username = getattr(_u[0], 'username', user_id) or user_id except Exception: pass client_ip = '' try: client_ip = request.get('client_ip', '') or '' except Exception: pass # 权限校验:所有 action 仅 owner.audit(superuser 也不行) async with get_sor_context(request._run_ns, 'pipeline') as _sor: if not await is_audit_role(_sor, user_id): return json.dumps({'ok': False, 'error': '仅 owner.audit 角色可访问审计日志'}, ensure_ascii=False) if action == 'list': filters = { 'user_id': (params_kw or {}).get('user_id', ''), 'username': (params_kw or {}).get('username', ''), 'action': (params_kw or {}).get('act', ''), 'from': (params_kw or {}).get('from', ''), 'to': (params_kw or {}).get('to', ''), } limit = (params_kw or {}).get('limit', 100) offset = (params_kw or {}).get('offset', 0) try: async with get_sor_context(request._run_ns, 'pipeline') as sor: rows = await list_audit_logs(sor, filters, limit, offset) return json.dumps({'ok': True, 'logs': rows}, ensure_ascii=False) except Exception as e: return json.dumps({'ok': False, 'error': str(e)}, ensure_ascii=False) elif action == 'backup': try: async with get_sor_context(request._run_ns, 'pipeline') as sor: r = await backup_audit_logs(sor, user_id, username, None, client_ip) return json.dumps(r, ensure_ascii=False) except Exception as e: return json.dumps({'ok': False, 'error': str(e)}, ensure_ascii=False) elif action == 'delete': before = (params_kw or {}).get('before', '') try: async with get_sor_context(request._run_ns, 'pipeline') as sor: r = await delete_audit_logs(sor, user_id, username, before, client_ip) return json.dumps(r, ensure_ascii=False) except Exception as e: return json.dumps({'ok': False, 'error': str(e)}, ensure_ascii=False) else: return json.dumps({'ok': False, 'error': '未知 action: ' + str(action)}, ensure_ascii=False)