185 lines
7.6 KiB
C#
185 lines
7.6 KiB
C#
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 Microsoft.EntityFrameworkCore;
|
|
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.IO.Compression;
|
|
using ChoETL;
|
|
|
|
namespace AyaNova.Api.Controllers
|
|
{
|
|
[ApiController]
|
|
[ApiVersion("8.0")]
|
|
[Route("api/v{version:apiVersion}/export")]
|
|
[Produces("application/json")]
|
|
[Authorize]
|
|
public class ExportController : ControllerBase
|
|
{
|
|
private readonly AyContext ct;
|
|
private readonly ILogger<ExportController> log;
|
|
private readonly ApiServerState serverState;
|
|
|
|
/// <summary>
|
|
/// ctor
|
|
/// </summary>
|
|
/// <param name="dbcontext"></param>
|
|
/// <param name="logger"></param>
|
|
/// <param name="apiServerState"></param>
|
|
public ExportController(AyContext dbcontext, ILogger<ExportController> logger, ApiServerState apiServerState)
|
|
{
|
|
ct = dbcontext;
|
|
log = logger;
|
|
serverState = apiServerState;
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Export to file
|
|
/// </summary>
|
|
/// <param name="format">Valid values are: "csv","json"</param>
|
|
/// <param name="selectedRequest"></param>
|
|
/// <returns>downloadable export file name</returns>
|
|
[HttpPost("render/{format}")]
|
|
public async Task<IActionResult> RenderExport([FromRoute] string format, [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.ObjectType))
|
|
return StatusCode(403, new ApiNotAuthorizedResponse());
|
|
|
|
if (string.IsNullOrWhiteSpace(format))
|
|
return BadRequest(new ApiErrorResponse(ApiErrorCode.VALIDATION_REQUIRED, null, "format required"));
|
|
|
|
if (format != "csv" && format != "json")
|
|
return BadRequest(new ApiErrorResponse(ApiErrorCode.VALIDATION_INVALID_VALUE, null, "format not valid, must be 'csv' or 'json'"));
|
|
|
|
|
|
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.ObjectType}");
|
|
var biz = BizObjectFactory.GetBizObject(selectedRequest.ObjectType, ct, UserId, UserRoles, UserTranslationId);
|
|
log.LogDebug($"Fetching data for {selectedRequest.SelectedRowIds.Length} {selectedRequest.ObjectType} items");
|
|
// var TheData = await ((IExportAbleObject)biz).GetJSONExportData(dataListSelection.SelectedRowIds);
|
|
|
|
string baseFileName = FileUtil.StringToSafeFileName($"{selectedRequest.ObjectType.ToString().ToLowerInvariant()}-{format}-{FileUtil.GetSafeDateFileName()}");
|
|
|
|
// string outputRandomFileNameNoExtension = StringUtil.ReplaceLastOccurrence(FileUtil.NewRandomFileName, ".", "");
|
|
string outputSourceFileName = baseFileName + "." + format;
|
|
string outputSourceFullPath = System.IO.Path.Combine(FileUtil.TemporaryFilesFolder, outputSourceFileName);
|
|
string outputZipFullpath = System.IO.Path.Combine(FileUtil.TemporaryFilesFolder, baseFileName + ".zip");
|
|
|
|
log.LogDebug($"Calling render export data to file {outputZipFullpath}");
|
|
switch (format)
|
|
{
|
|
case "csv":
|
|
using (var w = new ChoCSVWriter(outputSourceFullPath).WithFirstLineHeader())
|
|
{
|
|
var dat = await ((IExportAbleObject)biz).GetExportData(selectedRequest.SelectedRowIds);
|
|
w.Write(ToDynamicList(dat));
|
|
}
|
|
break;
|
|
case "json":
|
|
using (StreamWriter file = System.IO.File.CreateText(outputSourceFullPath))
|
|
using (JsonTextWriter writer = new JsonTextWriter(file))
|
|
{
|
|
var dat = await ((IExportAbleObject)biz).GetExportData(selectedRequest.SelectedRowIds);
|
|
dat.WriteTo(writer);
|
|
}
|
|
break;
|
|
}
|
|
|
|
//zip it
|
|
using (FileStream fs = new FileStream(outputZipFullpath, FileMode.Create))
|
|
using (ZipArchive arch = new ZipArchive(fs, ZipArchiveMode.Create))
|
|
{
|
|
arch.CreateEntryFromFile(outputSourceFullPath, outputSourceFileName);
|
|
}
|
|
|
|
log.LogDebug($"Completed, returning results");
|
|
return Ok(ApiOkResponse.Response(baseFileName + ".zip"));
|
|
|
|
|
|
}
|
|
|
|
public static IList<dynamic> ToDynamicList(JArray data)
|
|
{
|
|
var dynamicData = new List<dynamic>();
|
|
var expConverter = new Newtonsoft.Json.Converters.ExpandoObjectConverter();
|
|
|
|
foreach (var dataItem in data)
|
|
{
|
|
dynamic obj = JsonConvert.DeserializeObject<System.Dynamic.ExpandoObject>(dataItem.ToString(), expConverter);
|
|
dynamicData.Add(obj);
|
|
}
|
|
return dynamicData;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Download a rendered Export
|
|
/// </summary>
|
|
/// <param name="fileName"></param>
|
|
/// <param name="t">download token</param>
|
|
/// <returns></returns>
|
|
[HttpGet("download/{fileName}")]
|
|
[AllowAnonymous]
|
|
public async Task<IActionResult> 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);
|
|
return PhysicalFile(FilePath, "application/zip");
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
}//eoc
|
|
}//eons |