Files
tnsu-approval-route/backend/Tnsu.ApprovalRoute.Api/Controllers/ReportsController.cs
T
gorbenko.pavel e2b6227015
Tests / frontend-test (push) Successful in 47s
Tests / backend-test (push) Successful in 4m55s
Отчет по вакансиям (#20)
Co-authored-by: gorbenko.pavel <gorbenko.pavel@tansu.kz>
Reviewed-on: http://git.tnsu.kz/gorbenko.pavel/tnsu-approval-route/pulls/20
2026-08-31 11:00:09 +00:00

55 lines
2.6 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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) : 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);
}
}