using System.Collections.Generic; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Routing; using Microsoft.AspNetCore.Authorization; using Microsoft.Extensions.Logging; using AyaNova.Models; using AyaNova.Api.ControllerHelpers; using AyaNova.Biz; using AyaNova.Util; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System.IO; using System; namespace AyaNova.Api.Controllers { [ApiController] [Asp.Versioning.ApiVersion("8.0")] [Route("api/v{version:apiVersion}/export")] [Produces("application/json")] [Authorize] public class ExportController : ControllerBase { private readonly AyContext ct; private readonly ILogger log; private readonly ApiServerState serverState; /// /// ctor /// /// /// /// public ExportController(AyContext dbcontext, ILogger logger, ApiServerState apiServerState) { ct = dbcontext; log = logger; serverState = apiServerState; } /// /// Export to file /// /// /// downloadable export file name [HttpPost("render")] public async Task RenderExport([FromBody] DataListSelectedRequest selectedRequest) { if (!serverState.IsOpen) return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason)); if (!ModelState.IsValid) return BadRequest(new ApiErrorResponse(ModelState)); if (selectedRequest == null) return BadRequest(new ApiErrorResponse(ApiErrorCode.VALIDATION_REQUIRED, null, "DataListSelectedRequest is required")); if (!Authorized.HasReadFullRole(HttpContext.Items, selectedRequest.AType)) return StatusCode(403, new ApiNotAuthorizedResponse()); var UserId = UserIdFromContext.Id(HttpContext.Items); var UserRoles = UserRolesFromContext.Roles(HttpContext.Items); var UserTranslationId = UserTranslationIdFromContext.Id(HttpContext.Items); //Rehydrate id list if necessary if (selectedRequest.SelectedRowIds.Length == 0) selectedRequest.SelectedRowIds = await DataListSelectedProcessingOptions.RehydrateIdList( selectedRequest, ct, UserRoles, log, UserId, UserTranslationId); log.LogDebug($"Instantiating biz object handler for {selectedRequest.AType}"); var biz = BizObjectFactory.GetBizObject(selectedRequest.AType, ct, UserId, UserRoles, UserTranslationId); log.LogDebug($"Fetching data for {selectedRequest.SelectedRowIds.Length} {selectedRequest.AType} items"); string baseFileName = FileUtil.StringToSafeFileName($"{selectedRequest.AType.ToString().ToLowerInvariant()}-{FileUtil.GetSafeDateFileName()}"); string outputSourceFileName = baseFileName + ".json"; string outputSourceFullPath = System.IO.Path.Combine(FileUtil.TemporaryFilesFolder, outputSourceFileName); log.LogDebug($"Calling render export data to file {outputSourceFullPath}"); try { using (StreamWriter file = System.IO.File.CreateText(outputSourceFullPath)) using (JsonTextWriter writer = new JsonTextWriter(file)) { var dat = await ((IExportAbleObject)biz).GetExportData(selectedRequest, Guid.Empty);//todo: jobify dat.WriteTo(writer); } log.LogDebug($"Completed, returning results"); return Ok(ApiOkResponse.Response(outputSourceFileName)); } catch (ReportRenderTimeOutException) { log.LogInformation($"RenderExport timeout data list key: {selectedRequest.DataListKey}, record count:{selectedRequest.SelectedRowIds.LongLength}, user:{UserNameFromContext.Name(HttpContext.Items)} "); return BadRequest(new ApiErrorResponse(ApiErrorCode.INVALID_OPERATION, null, "timeout - select fewer records")); } } public static IList ToDynamicList(JArray data) { var dynamicData = new List(); var expConverter = new Newtonsoft.Json.Converters.ExpandoObjectConverter(); foreach (var dataItem in data) { dynamic obj = JsonConvert.DeserializeObject(dataItem.ToString(), expConverter); dynamicData.Add(obj); } return dynamicData; } /// /// Download a rendered Export /// /// /// download token /// [HttpGet("download/{fileName}")] [AllowAnonymous] public async Task DownloadAsync([FromRoute] string fileName, [FromQuery] string t) { if (!serverState.IsOpen) return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason)); if (await UserBiz.ValidateDownloadTokenAndReturnUserAsync(t, ct) == null) { await Task.Delay(ServerBootConfig.FAILED_AUTH_DELAY);//DOS protection return StatusCode(401, new ApiErrorResponse(ApiErrorCode.AUTHENTICATION_FAILED)); } if (!FileUtil.TemporaryFileExists(fileName)) { await Task.Delay(ServerBootConfig.FAILED_AUTH_DELAY);//fishing protection return NotFound(new ApiErrorResponse(ApiErrorCode.NOT_FOUND)); } var FilePath = FileUtil.GetFullPathForTemporaryFile(fileName); //including the file name triggers save automatically "attachment" rather than viewing it "inline" return PhysicalFile(FilePath, "application/json", fileName); } //----------------------------------------- }//eoc }//eons