This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using AutoMapper;
|
||||
using LaDOSE.Business.Interface;
|
||||
using LaDOSE.DTO;
|
||||
using LaDOSE.Entity;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace LaDOSE.Api.Controllers
|
||||
{
|
||||
/// <summary>
|
||||
/// Pushes ranking tables into the club's Google Spreadsheet.
|
||||
///
|
||||
/// The tables arrive already built: the browser reuses the same buildRanking() that produces
|
||||
/// the CSV export, so the sheet and the CSV cannot drift. This controller resolves the target
|
||||
/// from configuration, validates, and relays — see SheetsExportService.
|
||||
///
|
||||
/// Returns IActionResult with explicit ProducesResponseType, like UsersController: the API has
|
||||
/// no exception middleware, so an escaping throw reaches the browser as an HTML developer page
|
||||
/// that the client can only report as a bare status.
|
||||
/// </summary>
|
||||
[Authorize]
|
||||
[Produces("application/json")]
|
||||
[Route("api/[controller]")]
|
||||
public class SheetsController : ControllerBase
|
||||
{
|
||||
private readonly ISheetsExportService _service;
|
||||
private readonly IMapper _mapper;
|
||||
private readonly ILogger<SheetsController> _logger;
|
||||
|
||||
public SheetsController(IMapper mapper, ISheetsExportService service, ILogger<SheetsController> logger)
|
||||
{
|
||||
_mapper = mapper;
|
||||
_service = service;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether the export is usable and where it points, so the panel can render itself and
|
||||
/// disable the button when the server is not set up. Carries no secret and no key path.
|
||||
/// </summary>
|
||||
[HttpGet("Config")]
|
||||
[ProducesResponseType(typeof(SheetsConfigDTO), StatusCodes.Status200OK)]
|
||||
public IActionResult GetConfig()
|
||||
{
|
||||
return Ok(_mapper.Map<SheetsConfigDTO>(_service.GetConfig()));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes one tab per table, in the order given — oldest event first, each tab holding the
|
||||
/// cumulative result up to and including its own event.
|
||||
///
|
||||
/// Existing tabs of the same name are cleared and rewritten in place, keeping their
|
||||
/// formatting; anything typed into them by hand is lost. Tabs not named in the request are
|
||||
/// never touched or deleted.
|
||||
/// </summary>
|
||||
[HttpPost("Export")]
|
||||
[ProducesResponseType(typeof(SheetExportResultDTO), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||
[ProducesResponseType(StatusCodes.Status502BadGateway)]
|
||||
[ProducesResponseType(StatusCodes.Status503ServiceUnavailable)]
|
||||
public async Task<IActionResult> Export([FromBody] SheetExportRequestDTO dto, CancellationToken ct)
|
||||
{
|
||||
if (dto?.Tabs == null || dto.Tabs.Count == 0)
|
||||
return BadRequest(new { message = "No table to write." });
|
||||
|
||||
var request = _mapper.Map<SheetExportRequest>(dto);
|
||||
|
||||
try
|
||||
{
|
||||
var result = await _service.ExportAsync(request, ct);
|
||||
|
||||
_logger.LogInformation(
|
||||
"Sheets export by user {User}: {TabCount} tabs to spreadsheet {SpreadsheetId} via {Writer}",
|
||||
User?.Identity?.Name, result.Tabs?.Count ?? 0, result.SpreadsheetId, result.Writer);
|
||||
|
||||
return Ok(_mapper.Map<SheetExportResultDTO>(result));
|
||||
}
|
||||
catch (SheetsExportException ex)
|
||||
{
|
||||
_logger.LogWarning(ex, "Sheets export refused ({StatusCode})", ex.StatusCode);
|
||||
return StatusCode(ex.StatusCode, new { message = ex.Message });
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
// The caller navigated away or hit cancel; nothing to report to them.
|
||||
throw;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Anything unforeseen still has to arrive as JSON with a message.
|
||||
_logger.LogError(ex, "Sheets export failed");
|
||||
return StatusCode(StatusCodes.Status502BadGateway, new { message = ex.Message });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user