using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Tiku.Api.Contracts; using Tiku.Application.Growth; using Tiku.Application.Security; namespace Tiku.Api.Controllers; [ApiController] [Authorize(Policy = BackendPermissions.TenantCrmManage)] [Produces("application/json")] [Route("api/crm")] public sealed class CrmController( ICrmService crmService, ICurrentUser currentUser, ITenantContext currentTenant) : ControllerBase { [HttpGet("config")] [EndpointSummary("查询 CRM 推送配置")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task> Config(CancellationToken cancellationToken) { return Ok(await crmService.GetConfigAsync(ResolveActor(), cancellationToken)); } [HttpPut("config")] [EndpointSummary("保存 CRM 推送配置")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task> UpsertConfig( UpsertCrmConfigDto request, CancellationToken cancellationToken) { return Ok(await crmService.UpsertConfigAsync(ResolveActor(), request.ToCommand(), cancellationToken)); } [HttpGet("queue")] [EndpointSummary("查询 CRM webhook 队列")] [ProducesResponseType>(StatusCodes.Status200OK)] public async Task>> Queue( [FromQuery] CrmQueueQueryDto query, CancellationToken cancellationToken) { return Ok(await crmService.GetQueueAsync(ResolveActor(), query.ToQuery(), cancellationToken)); } [HttpGet("dead-letters")] [EndpointSummary("查询 CRM 死信任务与汇总")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task> DeadLetters( [FromQuery] CrmQueueQueryDto query, CancellationToken cancellationToken) { return Ok(await crmService.GetDeadLettersAsync(ResolveActor(), query.ToQuery(), cancellationToken)); } [HttpGet("queue/logs")] [EndpointSummary("查询 CRM 队列执行日志")] [ProducesResponseType>(StatusCodes.Status200OK)] public async Task>> Logs( [FromQuery] CrmQueueLogQueryDto query, CancellationToken cancellationToken) { return Ok(await crmService.GetLogsAsync(ResolveActor(), query.ToQuery(), cancellationToken)); } [HttpPost("queue/action")] [EndpointSummary("重试或忽略 CRM 死信任务")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task> Action( CrmQueueActionDto request, CancellationToken cancellationToken) { return Ok(await crmService.ApplyQueueActionAsync(ResolveActor(), request.ToCommand(), cancellationToken)); } private CrmAdminActor ResolveActor() { if (currentTenant.TenantId is null || currentUser.UserId is null) { throw new CrmException("CRM admin actor was not resolved.", "crm_access_denied"); } return new CrmAdminActor(currentTenant.TenantId.Value, currentUser.UserId.Value); } }