458 lines
16 KiB
Python
458 lines
16 KiB
Python
|
|
"""白名单域 Router(ALW-01~ALW-06 + P1缺口)。
|
|||
|
|
|
|||
|
|
本 router 实现渠道账户白名单条目的全部 HTTP 端点,覆盖查询 / 新增 /
|
|||
|
|
修改 / 删除 / 批量导入 / 导出 / 批量删除 / 清理过期共 8 个操作。所有端点
|
|||
|
|
统一采用模板 A(控制面端口路由),通过 ``get_channel_use_cases`` 装配
|
|||
|
|
``ChannelUseCases``,经 ``whitelist_management`` 端口调用类型化方法,由
|
|||
|
|
``ChannelControlService._executeControl`` 内部走控制面管道
|
|||
|
|
(auth → permission → rate_limit → dispatch → audit)。
|
|||
|
|
|
|||
|
|
鉴权策略:全部端点使用 ``get_admin_user`` 依赖,要求管理员或超级管理员角色。
|
|||
|
|
角色校验由依赖函数完成,router 内不做角色判断(规范 §4)。
|
|||
|
|
|
|||
|
|
路径设计:``/batch`` / ``/export`` / ``/batch-delete`` / ``/clean-expired``
|
|||
|
|
静态后缀先于 ``/{peer_id}`` 动态路径声明(规范 §6.5),避免静态路径被动态
|
|||
|
|
参数捕获。子 router 不自行设置 prefix,根前缀 ``/channels`` 由
|
|||
|
|
``channels_router`` 聚合 router 统一追加。
|
|||
|
|
|
|||
|
|
端点清单(对应本设计方案 §2.1 + P1缺口补全):
|
|||
|
|
- GET /{channel_type}/{account_id}/allowlist/{policy_type} ALW-01 list_whitelist
|
|||
|
|
- POST /{channel_type}/{account_id}/allowlist/{policy_type} ALW-02 add_whitelist_entry
|
|||
|
|
- POST /{channel_type}/{account_id}/allowlist/{policy_type}/batch ALW-05 batch_add_whitelist
|
|||
|
|
- GET /{channel_type}/{account_id}/allowlist/{policy_type}/export ALW-06 export_whitelist
|
|||
|
|
- POST /{channel_type}/{account_id}/allowlist/{policy_type}/batch-delete ALW-BATCH-DEL 批量删除白名单
|
|||
|
|
- POST /{channel_type}/{account_id}/allowlist/{policy_type}/clean-expired ALW-CLEAN-EXPIRED 清理过期白名单
|
|||
|
|
- PUT /{channel_type}/{account_id}/allowlist/{policy_type}/{peer_id} ALW-03 update_whitelist_entry
|
|||
|
|
- DELETE /{channel_type}/{account_id}/allowlist/{policy_type}/{peer_id} ALW-04 remove_whitelist_entry
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
from __future__ import annotations
|
|||
|
|
|
|||
|
|
from typing import Any
|
|||
|
|
|
|||
|
|
from fastapi import APIRouter, Depends, Query, Request
|
|||
|
|
from pydantic import BaseModel, ConfigDict, Field
|
|||
|
|
|
|||
|
|
from yuxi.channels.contract.dtos.channel import ChannelType
|
|||
|
|
from yuxi.channels.contract.dtos.whitelist import (
|
|||
|
|
BatchWhitelistDeleteCmd,
|
|||
|
|
CleanExpiredWhitelistCmd,
|
|||
|
|
WhitelistEntry,
|
|||
|
|
WhitelistPolicyType,
|
|||
|
|
)
|
|||
|
|
from yuxi.channels.contract.errors import ValidationError
|
|||
|
|
from yuxi.storage.postgres.models_business import User
|
|||
|
|
|
|||
|
|
from server.routers.channels import (
|
|||
|
|
build_operator,
|
|||
|
|
get_channel_use_cases,
|
|||
|
|
parse_datetime,
|
|||
|
|
raiseOnControlFailure,
|
|||
|
|
serialize_control_data,
|
|||
|
|
)
|
|||
|
|
from server.utils.auth_middleware import get_admin_user
|
|||
|
|
|
|||
|
|
allowlist_router = APIRouter(tags=["channels-allowlist"])
|
|||
|
|
|
|||
|
|
|
|||
|
|
def _parse_policy_type(raw: str) -> WhitelistPolicyType:
|
|||
|
|
"""string → WhitelistPolicyType,失败抛 ValidationError。"""
|
|||
|
|
try:
|
|||
|
|
return WhitelistPolicyType(raw)
|
|||
|
|
except ValueError as exc:
|
|||
|
|
raise ValidationError(
|
|||
|
|
"policy_type",
|
|||
|
|
f"unsupported policy_type: {raw} (expected: dm | group)",
|
|||
|
|
) from exc
|
|||
|
|
|
|||
|
|
|
|||
|
|
def _parse_export_format(raw: str) -> str:
|
|||
|
|
"""校验导出格式参数,失败抛 ValidationError。
|
|||
|
|
|
|||
|
|
仅允许 ``json`` / ``csv`` 两种取值,原样返回(无需类型转换)。
|
|||
|
|
"""
|
|||
|
|
if raw not in ("json", "csv"):
|
|||
|
|
raise ValidationError(
|
|||
|
|
"format",
|
|||
|
|
f"unsupported format: {raw} (expected: json | csv)",
|
|||
|
|
)
|
|||
|
|
return raw
|
|||
|
|
|
|||
|
|
|
|||
|
|
class WhitelistAddRequest(BaseModel):
|
|||
|
|
"""新增白名单条目请求。字段对齐 ``WhitelistManagementPort.addWhitelistEntry`` 入参。"""
|
|||
|
|
|
|||
|
|
model_config = ConfigDict(frozen=True)
|
|||
|
|
|
|||
|
|
peer_id: str = Field(..., description="对端 ID")
|
|||
|
|
peer_name: str | None = Field(default=None, description="对端名称")
|
|||
|
|
reason: str | None = Field(default=None, description="加白原因")
|
|||
|
|
expires_at: str | None = Field(
|
|||
|
|
default=None,
|
|||
|
|
description="过期时间(ISO 8601),缺失表示永久",
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
|
|||
|
|
class WhitelistUpdateRequest(BaseModel):
|
|||
|
|
"""修改白名单条目请求(PATCH 语义)。
|
|||
|
|
|
|||
|
|
支持修改 ``peer_name`` / ``reason`` / ``expires_at`` 三字段;
|
|||
|
|
``peer_id`` 与 ``policy_type`` 为路径参数不可变更。字段缺失(``None``)
|
|||
|
|
表示不修改该字段,保留原值;如需清除 ``expires_at``(设为永久),
|
|||
|
|
请使用删除 + 重新添加流程。
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
model_config = ConfigDict(frozen=True)
|
|||
|
|
|
|||
|
|
peer_name: str | None = Field(default=None, description="对端名称(None=不修改)")
|
|||
|
|
reason: str | None = Field(default=None, description="加白原因(None=不修改)")
|
|||
|
|
expires_at: str | None = Field(
|
|||
|
|
default=None,
|
|||
|
|
description="过期时间(ISO 8601),None=不修改保留原值",
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
|
|||
|
|
class WhitelistBatchItem(BaseModel):
|
|||
|
|
"""批量导入白名单条目项。"""
|
|||
|
|
|
|||
|
|
model_config = ConfigDict(frozen=True)
|
|||
|
|
|
|||
|
|
peer_id: str = Field(..., description="对端 ID")
|
|||
|
|
peer_name: str | None = Field(default=None, description="对端名称")
|
|||
|
|
reason: str | None = Field(default=None, description="加白原因")
|
|||
|
|
expires_at: str | None = Field(default=None, description="过期时间(ISO 8601)")
|
|||
|
|
|
|||
|
|
|
|||
|
|
class WhitelistBatchRequest(BaseModel):
|
|||
|
|
"""批量导入白名单请求。
|
|||
|
|
|
|||
|
|
``items`` 长度上限 500(规范 §2.3.5),``stop_on_error`` 默认 False
|
|||
|
|
跳过失败项继续导入。
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
model_config = ConfigDict(frozen=True)
|
|||
|
|
|
|||
|
|
items: list[WhitelistBatchItem] = Field(
|
|||
|
|
...,
|
|||
|
|
min_length=1,
|
|||
|
|
max_length=500,
|
|||
|
|
description="批量条目(上限 500)",
|
|||
|
|
)
|
|||
|
|
stop_on_error: bool = Field(
|
|||
|
|
default=False,
|
|||
|
|
description="是否在首条失败时终止;默认 False 跳过失败项继续导入",
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
|
|||
|
|
class WhitelistBatchDeleteRequest(BaseModel):
|
|||
|
|
"""批量删除白名单条目请求(ALW-BATCH-DEL)。"""
|
|||
|
|
|
|||
|
|
model_config = ConfigDict(frozen=True)
|
|||
|
|
|
|||
|
|
peer_ids: list[str] = Field(
|
|||
|
|
...,
|
|||
|
|
min_length=1,
|
|||
|
|
max_length=500,
|
|||
|
|
description="待删除对端 ID 列表(上限 500)",
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
|
|||
|
|
class WhitelistCleanExpiredRequest(BaseModel):
|
|||
|
|
"""清理过期白名单条目请求(ALW-CLEAN-EXPIRED)。"""
|
|||
|
|
|
|||
|
|
model_config = ConfigDict(frozen=True)
|
|||
|
|
|
|||
|
|
older_than: str | None = Field(
|
|||
|
|
default=None,
|
|||
|
|
description="过期阈值(ISO 8601),缺失取当前时间",
|
|||
|
|
)
|
|||
|
|
max_count: int = Field(
|
|||
|
|
default=500,
|
|||
|
|
ge=1,
|
|||
|
|
le=1000,
|
|||
|
|
description="单次最大清理数(1-1000,默认 500)",
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
|
|||
|
|
@allowlist_router.get(
|
|||
|
|
"/{channel_type}/{account_id}/allowlist/{policy_type}",
|
|||
|
|
response_model=dict,
|
|||
|
|
)
|
|||
|
|
async def list_whitelist(
|
|||
|
|
channel_type: ChannelType,
|
|||
|
|
account_id: str,
|
|||
|
|
policy_type: str,
|
|||
|
|
request: Request,
|
|||
|
|
use_cases=Depends(get_channel_use_cases),
|
|||
|
|
current_user: User = Depends(get_admin_user),
|
|||
|
|
) -> dict[str, Any]:
|
|||
|
|
"""查询白名单条目列表(FR-18 / AC-42)。
|
|||
|
|
|
|||
|
|
``policy_type`` 非法时返回 400。对应控制面操作 ``whitelist/list``。
|
|||
|
|
"""
|
|||
|
|
operator = build_operator(current_user, request)
|
|||
|
|
policy = _parse_policy_type(policy_type)
|
|||
|
|
result = await use_cases.whitelist_management.listWhitelist(
|
|||
|
|
channel_type=channel_type,
|
|||
|
|
account_id=account_id,
|
|||
|
|
policy_type=policy,
|
|||
|
|
operator=operator,
|
|||
|
|
)
|
|||
|
|
raiseOnControlFailure(result)
|
|||
|
|
return {"success": True, "data": serialize_control_data(result.data)}
|
|||
|
|
|
|||
|
|
|
|||
|
|
@allowlist_router.post(
|
|||
|
|
"/{channel_type}/{account_id}/allowlist/{policy_type}",
|
|||
|
|
response_model=dict,
|
|||
|
|
)
|
|||
|
|
async def add_whitelist_entry(
|
|||
|
|
channel_type: ChannelType,
|
|||
|
|
account_id: str,
|
|||
|
|
policy_type: str,
|
|||
|
|
payload: WhitelistAddRequest,
|
|||
|
|
request: Request,
|
|||
|
|
use_cases=Depends(get_channel_use_cases),
|
|||
|
|
current_user: User = Depends(get_admin_user),
|
|||
|
|
) -> dict[str, Any]:
|
|||
|
|
"""新增白名单条目(FR-18 / AC-20 / AC-42 / AC-65)。"""
|
|||
|
|
operator = build_operator(current_user, request)
|
|||
|
|
policy = _parse_policy_type(policy_type)
|
|||
|
|
expires_at = parse_datetime("expires_at", payload.expires_at)
|
|||
|
|
entry = WhitelistEntry(
|
|||
|
|
peer_id=payload.peer_id,
|
|||
|
|
peer_type=policy,
|
|||
|
|
peer_name=payload.peer_name,
|
|||
|
|
reason=payload.reason,
|
|||
|
|
expires_at=expires_at,
|
|||
|
|
)
|
|||
|
|
result = await use_cases.whitelist_management.addWhitelistEntry(
|
|||
|
|
channel_type=channel_type,
|
|||
|
|
account_id=account_id,
|
|||
|
|
entry=entry,
|
|||
|
|
operator=operator,
|
|||
|
|
)
|
|||
|
|
raiseOnControlFailure(result)
|
|||
|
|
return {"success": True, "data": serialize_control_data(result.data)}
|
|||
|
|
|
|||
|
|
|
|||
|
|
@allowlist_router.post(
|
|||
|
|
"/{channel_type}/{account_id}/allowlist/{policy_type}/batch",
|
|||
|
|
response_model=dict,
|
|||
|
|
)
|
|||
|
|
async def batch_add_whitelist(
|
|||
|
|
channel_type: ChannelType,
|
|||
|
|
account_id: str,
|
|||
|
|
policy_type: str,
|
|||
|
|
payload: WhitelistBatchRequest,
|
|||
|
|
request: Request,
|
|||
|
|
use_cases=Depends(get_channel_use_cases),
|
|||
|
|
current_user: User = Depends(get_admin_user),
|
|||
|
|
) -> dict[str, Any]:
|
|||
|
|
"""批量导入白名单条目(FR-18)。
|
|||
|
|
|
|||
|
|
支持两种语义:
|
|||
|
|
- ``stop_on_error=True``:首条失败即终止,整批回滚(按异常抛出)
|
|||
|
|
- ``stop_on_error=False``(默认):跳过失败项,响应中返回成功与失败列表
|
|||
|
|
|
|||
|
|
单批上限 500 条,超过返回 422 ``VALIDATION_ERROR``。
|
|||
|
|
"""
|
|||
|
|
operator = build_operator(current_user, request)
|
|||
|
|
policy = _parse_policy_type(policy_type)
|
|||
|
|
entries = tuple(
|
|||
|
|
WhitelistEntry(
|
|||
|
|
peer_id=item.peer_id,
|
|||
|
|
peer_type=policy,
|
|||
|
|
peer_name=item.peer_name,
|
|||
|
|
reason=item.reason,
|
|||
|
|
expires_at=_parse_expires_at(item.expires_at),
|
|||
|
|
)
|
|||
|
|
for item in payload.items
|
|||
|
|
)
|
|||
|
|
result = await use_cases.whitelist_management.batchAddWhitelistEntries(
|
|||
|
|
channel_type=channel_type,
|
|||
|
|
account_id=account_id,
|
|||
|
|
policy_type=policy,
|
|||
|
|
entries=entries,
|
|||
|
|
stop_on_error=payload.stop_on_error,
|
|||
|
|
operator=operator,
|
|||
|
|
)
|
|||
|
|
raiseOnControlFailure(result)
|
|||
|
|
return {"success": True, "data": serialize_control_data(result.data)}
|
|||
|
|
|
|||
|
|
|
|||
|
|
@allowlist_router.get(
|
|||
|
|
"/{channel_type}/{account_id}/allowlist/{policy_type}/export",
|
|||
|
|
response_model=dict,
|
|||
|
|
)
|
|||
|
|
async def export_whitelist(
|
|||
|
|
channel_type: ChannelType,
|
|||
|
|
account_id: str,
|
|||
|
|
policy_type: str,
|
|||
|
|
request: Request,
|
|||
|
|
format: str = Query(default="json", description="导出格式:json / csv"),
|
|||
|
|
use_cases=Depends(get_channel_use_cases),
|
|||
|
|
current_user: User = Depends(get_admin_user),
|
|||
|
|
) -> dict[str, Any]:
|
|||
|
|
"""导出白名单条目(FR-18)。
|
|||
|
|
|
|||
|
|
支持 ``json`` / ``csv`` 两种格式:
|
|||
|
|
- ``json``:返回结构化 JSON 数组
|
|||
|
|
- ``csv``:返回 ``data.content`` 为 CSV 字符串,``data.filename`` 为建议文件名
|
|||
|
|
"""
|
|||
|
|
operator = build_operator(current_user, request)
|
|||
|
|
policy = _parse_policy_type(policy_type)
|
|||
|
|
fmt = _parse_export_format(format)
|
|||
|
|
result = await use_cases.whitelist_management.exportWhitelist(
|
|||
|
|
channel_type=channel_type,
|
|||
|
|
account_id=account_id,
|
|||
|
|
policy_type=policy,
|
|||
|
|
format=fmt,
|
|||
|
|
operator=operator,
|
|||
|
|
)
|
|||
|
|
raiseOnControlFailure(result)
|
|||
|
|
return {"success": True, "data": serialize_control_data(result.data)}
|
|||
|
|
|
|||
|
|
|
|||
|
|
@allowlist_router.post(
|
|||
|
|
"/{channel_type}/{account_id}/allowlist/{policy_type}/batch-delete",
|
|||
|
|
response_model=dict,
|
|||
|
|
)
|
|||
|
|
async def batch_delete_whitelist(
|
|||
|
|
channel_type: ChannelType,
|
|||
|
|
account_id: str,
|
|||
|
|
policy_type: str,
|
|||
|
|
payload: WhitelistBatchDeleteRequest,
|
|||
|
|
request: Request,
|
|||
|
|
use_cases=Depends(get_channel_use_cases),
|
|||
|
|
current_user: User = Depends(get_admin_user),
|
|||
|
|
) -> dict[str, Any]:
|
|||
|
|
"""批量删除白名单条目(ALW-BATCH-DEL)。
|
|||
|
|
|
|||
|
|
逐条独立事务删除(模式 D 部分成功语义),复用单条 ``whitelist/remove``
|
|||
|
|
逻辑。单批上限 500 条,单条失败不回滚已成功条目。对应控制面操作
|
|||
|
|
``whitelist/batch_delete``。
|
|||
|
|
|
|||
|
|
响应:``{total, deleted: [peer_id, ...], failed: [{id, error_code, message}, ...]}``。
|
|||
|
|
"""
|
|||
|
|
operator = build_operator(current_user, request)
|
|||
|
|
policy = _parse_policy_type(policy_type)
|
|||
|
|
cmd = BatchWhitelistDeleteCmd(
|
|||
|
|
channel_type=channel_type,
|
|||
|
|
account_id=account_id,
|
|||
|
|
policy_type=policy,
|
|||
|
|
operator=operator,
|
|||
|
|
peer_ids=tuple(payload.peer_ids),
|
|||
|
|
)
|
|||
|
|
result = await use_cases.whitelist_management.batchDeleteWhitelist(cmd)
|
|||
|
|
raiseOnControlFailure(result)
|
|||
|
|
return {"success": True, "data": serialize_control_data(result.data)}
|
|||
|
|
|
|||
|
|
|
|||
|
|
@allowlist_router.post(
|
|||
|
|
"/{channel_type}/{account_id}/allowlist/{policy_type}/clean-expired",
|
|||
|
|
response_model=dict,
|
|||
|
|
)
|
|||
|
|
async def clean_expired_whitelist(
|
|||
|
|
channel_type: ChannelType,
|
|||
|
|
account_id: str,
|
|||
|
|
policy_type: str,
|
|||
|
|
payload: WhitelistCleanExpiredRequest,
|
|||
|
|
request: Request,
|
|||
|
|
use_cases=Depends(get_channel_use_cases),
|
|||
|
|
current_user: User = Depends(get_admin_user),
|
|||
|
|
) -> dict[str, Any]:
|
|||
|
|
"""清理过期白名单条目(ALW-CLEAN-EXPIRED)。
|
|||
|
|
|
|||
|
|
查询过期白名单条目(``expires_at < older_than``,缺省取当前时间)并
|
|||
|
|
批量删除(单一事务 COOPERATIVE fail-closed)。``max_count`` 限制单次
|
|||
|
|
最大清理数(1-1000,默认 500)。对应控制面操作 ``whitelist/clean_expired``。
|
|||
|
|
|
|||
|
|
响应:``{total, cleaned}``。
|
|||
|
|
"""
|
|||
|
|
operator = build_operator(current_user, request)
|
|||
|
|
policy = _parse_policy_type(policy_type)
|
|||
|
|
cmd = CleanExpiredWhitelistCmd(
|
|||
|
|
channel_type=channel_type,
|
|||
|
|
account_id=account_id,
|
|||
|
|
policy_type=policy,
|
|||
|
|
operator=operator,
|
|||
|
|
older_than=parse_datetime("older_than", payload.older_than),
|
|||
|
|
max_count=payload.max_count,
|
|||
|
|
)
|
|||
|
|
result = await use_cases.whitelist_management.cleanExpiredWhitelist(cmd)
|
|||
|
|
raiseOnControlFailure(result)
|
|||
|
|
return {"success": True, "data": serialize_control_data(result.data)}
|
|||
|
|
|
|||
|
|
|
|||
|
|
@allowlist_router.put(
|
|||
|
|
"/{channel_type}/{account_id}/allowlist/{policy_type}/{peer_id}",
|
|||
|
|
response_model=dict,
|
|||
|
|
)
|
|||
|
|
async def update_whitelist_entry(
|
|||
|
|
channel_type: ChannelType,
|
|||
|
|
account_id: str,
|
|||
|
|
policy_type: str,
|
|||
|
|
peer_id: str,
|
|||
|
|
payload: WhitelistUpdateRequest,
|
|||
|
|
request: Request,
|
|||
|
|
use_cases=Depends(get_channel_use_cases),
|
|||
|
|
current_user: User = Depends(get_admin_user),
|
|||
|
|
) -> dict[str, Any]:
|
|||
|
|
"""修改白名单条目(FR-18 / AC-41 / AC-42)。
|
|||
|
|
|
|||
|
|
支持修改 ``peer_name`` / ``reason`` / ``expires_at`` 三字段;
|
|||
|
|
``peer_id`` 与 ``policy_type`` 为路径参数,不可变更。
|
|||
|
|
条目不存在时返回 404(AC-41)。
|
|||
|
|
"""
|
|||
|
|
operator = build_operator(current_user, request)
|
|||
|
|
policy = _parse_policy_type(policy_type)
|
|||
|
|
expires_at = parse_datetime("expires_at", payload.expires_at)
|
|||
|
|
result = await use_cases.whitelist_management.updateWhitelistEntry(
|
|||
|
|
channel_type=channel_type,
|
|||
|
|
account_id=account_id,
|
|||
|
|
peer_id=peer_id,
|
|||
|
|
policy_type=policy,
|
|||
|
|
peer_name=payload.peer_name,
|
|||
|
|
reason=payload.reason,
|
|||
|
|
expires_at=expires_at,
|
|||
|
|
operator=operator,
|
|||
|
|
)
|
|||
|
|
raiseOnControlFailure(result)
|
|||
|
|
return {"success": True, "data": serialize_control_data(result.data)}
|
|||
|
|
|
|||
|
|
|
|||
|
|
@allowlist_router.delete(
|
|||
|
|
"/{channel_type}/{account_id}/allowlist/{policy_type}/{peer_id}",
|
|||
|
|
response_model=dict,
|
|||
|
|
)
|
|||
|
|
async def remove_whitelist_entry(
|
|||
|
|
channel_type: ChannelType,
|
|||
|
|
account_id: str,
|
|||
|
|
policy_type: str,
|
|||
|
|
peer_id: str,
|
|||
|
|
request: Request,
|
|||
|
|
use_cases=Depends(get_channel_use_cases),
|
|||
|
|
current_user: User = Depends(get_admin_user),
|
|||
|
|
) -> dict[str, Any]:
|
|||
|
|
"""删除白名单条目(FR-18 / AC-41 / AC-42)。
|
|||
|
|
|
|||
|
|
``peer_id`` 与 ``policy_type`` 为路径参数,联合定位唯一条目。
|
|||
|
|
条目不存在时返回 404(AC-41);删除成功后立即触发 ``ConfigChanged``
|
|||
|
|
事件,``WhitelistRegistry`` 同步移除(<1s,FR-37)。
|
|||
|
|
"""
|
|||
|
|
operator = build_operator(current_user, request)
|
|||
|
|
policy = _parse_policy_type(policy_type)
|
|||
|
|
result = await use_cases.whitelist_management.removeWhitelistEntry(
|
|||
|
|
channel_type=channel_type,
|
|||
|
|
account_id=account_id,
|
|||
|
|
peer_id=peer_id,
|
|||
|
|
policy_type=policy,
|
|||
|
|
operator=operator,
|
|||
|
|
)
|
|||
|
|
raiseOnControlFailure(result)
|
|||
|
|
return {
|
|||
|
|
"success": True,
|
|||
|
|
"data": serialize_control_data(result.data) if result.data else {},
|
|||
|
|
}
|