using System.Text.Json; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Tiku.Api.Contracts; using Tiku.Api.Security; using Tiku.Application.Assets; using Tiku.Application.Catalog; using Tiku.Application.Content; using Tiku.Application.Jobs; using Tiku.Application.Security; using Tiku.Domain.Catalog; using Tiku.Domain.Content; namespace Tiku.Api.Controllers; [ApiController] [Tags("租户端-内容直接管理")] [Produces("application/json")] [Route("api/tenant/content")] public sealed class ContentImportController( IContentImportService service, IBackgroundJobQueue backgroundJobService, DirectContentActorResolver actorResolver) : ControllerBase { [HttpPost("imports/preview/{importType}")] [Authorize(Policy = BackendPermissions.TenantJobManage)] [Authorize(Policy = TikuPolicies.TenantAllDataScope)] [RequireSaasFeatureFromRoute("importType")] [EndpointSummary("预览内容导入数据")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task> PreviewImport( string importType, DirectImportDto request, CancellationToken cancellationToken) { return Ok(await service.PreviewImportAsync(actorResolver.Resolve(), request.ToCommand(importType, true), cancellationToken)); } [HttpPost("imports/{importType}")] [Authorize(Policy = BackendPermissions.TenantJobManage)] [Authorize(Policy = TikuPolicies.TenantAllDataScope)] [RequireSaasFeatureFromRoute("importType")] [EndpointSummary("执行或排队内容导入")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status202Accepted)] public async Task> ExecuteImport( string importType, DirectImportDto request, CancellationToken cancellationToken) { var actor = actorResolver.Resolve(); var command = request.ToCommand(importType, false); if (request.Async == true || command.Items.Count > 100) { var job = await backgroundJobService.EnqueueAsync( new CreateBackgroundJobCommand( actor.TenantId, "content_import", JsonSerializer.SerializeToElement(new { createdBy = actor.UserId, importType = command.ImportType, sourceFormat = command.SourceFormat, sourceName = command.SourceName, regionId = command.RegionId, entryId = command.EntryId, contentNodeId = command.ContentNodeId, subjectId = command.SubjectId, categoryId = command.CategoryId, questionBankId = command.QuestionBankId, collectionId = command.CollectionId, items = command.Items })), cancellationToken); return Accepted(job); } return Ok(await service.ExecuteImportAsync(actor, command, cancellationToken)); } [HttpGet("imports/detail")] [Authorize(Policy = BackendPermissions.TenantJobManage)] [Authorize(Policy = TikuPolicies.TenantAllDataScope)] [EndpointSummary("查询内容导入任务详情")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task> GetImportDetail( [FromQuery] DirectImportJobDto query, CancellationToken cancellationToken) { return Ok(await service.GetImportJobAsync(actorResolver.Resolve(), query.JobId, cancellationToken)); } [HttpGet("imports/issues")] [Authorize(Policy = BackendPermissions.TenantJobManage)] [Authorize(Policy = TikuPolicies.TenantAllDataScope)] [EndpointSummary("查询内容导入问题明细")] [ProducesResponseType>(StatusCodes.Status200OK)] public async Task>> GetImportIssues( [FromQuery] DirectImportJobDto query, CancellationToken cancellationToken) { return Ok(await service.GetImportIssuesAsync(actorResolver.Resolve(), query.JobId, cancellationToken)); } [HttpPost("imports/post-check")] [Authorize(Policy = BackendPermissions.TenantJobManage)] [Authorize(Policy = TikuPolicies.TenantAllDataScope)] [EndpointSummary("执行内容导入后完整性检查")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task> RunImportPostCheck( DirectImportJobDto request, CancellationToken cancellationToken) { return Ok(await service.RunImportPostCheckAsync(actorResolver.Resolve(), request.JobId, cancellationToken)); } [HttpGet("imports/post-check")] [Authorize(Policy = BackendPermissions.TenantJobManage)] [Authorize(Policy = TikuPolicies.TenantAllDataScope)] [EndpointSummary("查询内容导入后检查状态")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task> GetImportPostCheck( [FromQuery] DirectImportJobDto query, CancellationToken cancellationToken) { return Ok(await service.GetImportPostCheckAsync(actorResolver.Resolve(), query.JobId, cancellationToken)); } }