0e6a7064d2
Co-authored-by: gorbenko.pavel <gorbenko.pavel@tansu.kz> Reviewed-on: http://git.tnsu.kz/gorbenko.pavel/tnsu-approval-route/pulls/29
78 lines
3.7 KiB
C#
78 lines
3.7 KiB
C#
using System.Globalization;
|
||
using Microsoft.AspNetCore.Authorization;
|
||
using Microsoft.AspNetCore.Mvc;
|
||
using Microsoft.Net.Http.Headers;
|
||
using Tnsu.ApprovalRoute.Api.Auth;
|
||
using Tnsu.ApprovalRoute.Application.Reports;
|
||
|
||
namespace Tnsu.ApprovalRoute.Api.Controllers;
|
||
|
||
/// <summary>
|
||
/// Выгрузки отчётов файлами. В отличие от остальных контроллеров отдаёт не
|
||
/// ApiResponse, а сам файл: получатель — кнопка «скачать» в портале и Power
|
||
/// Automate, обоим нужен готовый xlsx, а не JSON с телом в base64.
|
||
/// </summary>
|
||
[ApiController]
|
||
[Authorize(Policy = AuthPolicies.Any)]
|
||
[Route("api/reports")]
|
||
public sealed class ReportsController(VacancyReportService vacancies, RouteExportService routeExport) : ControllerBase
|
||
{
|
||
private const string XlsxContentType =
|
||
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
|
||
|
||
/// <summary>
|
||
/// Отчёт по вакансиям за период — лист «Список вакансий (все)» по данным
|
||
/// заявок на подбор и на приём.
|
||
///
|
||
/// Период отбирает заявки по «Дате подачи заявки» (колонка H отчёта). Заявки
|
||
/// на приём периодом НЕ ограничены: у вакансии, поданной в начале интервала,
|
||
/// приём мог оформляться уже после его конца.
|
||
/// </summary>
|
||
[HttpGet("vacancies")]
|
||
[Produces(XlsxContentType)]
|
||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||
public async Task<IActionResult> Vacancies(
|
||
[FromQuery] DateOnly from, [FromQuery] DateOnly to, CancellationToken ct = default)
|
||
{
|
||
var result = await vacancies.GetAsync(from, to, ct);
|
||
if (result.IsFailed)
|
||
return BadRequest(new { errors = result.Errors.Select(e => e.Message) });
|
||
|
||
var report = result.Value;
|
||
var file = VacancyReportWorkbook.Build(report);
|
||
|
||
// Имя файла с кириллицей и пробелами — через ContentDispositionHeaderValue:
|
||
// он сам добавит filename* в RFC 5987, иначе браузер сохранит файл
|
||
// с искажённым именем.
|
||
var disposition = new ContentDispositionHeaderValue("attachment");
|
||
disposition.SetHttpFileName(VacancyReportWorkbook.FileName(report));
|
||
Response.Headers.ContentDisposition = disposition.ToString();
|
||
|
||
return File(file, XlsxContentType);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Выгрузка маршрутов согласования выбранных типов заявок в xlsx (лист на тип).
|
||
/// POST — потому что в теле список id типов (см. RouteExportService).
|
||
/// </summary>
|
||
[HttpPost("routes")]
|
||
[Produces(XlsxContentType)]
|
||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||
public async Task<IActionResult> Routes([FromBody] RouteExportRequest request, CancellationToken ct = default)
|
||
{
|
||
var result = await routeExport.BuildAsync(request.RequestTypeIds, ct);
|
||
if (result.IsFailed)
|
||
return BadRequest(new { errors = result.Errors.Select(e => e.Message) });
|
||
|
||
var file = result.Value;
|
||
|
||
var disposition = new ContentDispositionHeaderValue("attachment");
|
||
disposition.SetHttpFileName(file.FileName);
|
||
Response.Headers.ContentDisposition = disposition.ToString();
|
||
|
||
return File(file.Content, XlsxContentType);
|
||
}
|
||
}
|