Refactor: Rename DocumentOperator to DocumentService
Updated project and solution files to rename and restructure `DocumentOperator` to `DocumentService`. Modified project references in `DocumentService.API.csproj`, `DocumentService.Application.csproj`, and `DocumentService.Infrastructure.csproj` to reflect the new naming convention. Updated `DocumentService.sln` to remove old project references, add new ones, and adjust configuration and nested project mappings accordingly. This change aligns the project structure with the new naming convention.
This commit is contained in:
179
DocumentService.API/Controllers/ZugferdController.cs
Normal file
179
DocumentService.API/Controllers/ZugferdController.cs
Normal file
@@ -0,0 +1,179 @@
|
||||
using DocumentService.Application.Common.DTOs;
|
||||
using DocumentService.Application.ExtractZugferd;
|
||||
using DocumentService.Application.HasZugferd.Queries;
|
||||
using DocumentService.Client.Models.Requests;
|
||||
using DocumentService.Domain.Common.Exceptions;
|
||||
using MediatR;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace DocumentService.API.Controllers;
|
||||
|
||||
/// <summary>
|
||||
/// Controller for ZUGFeRD operations (detection, extraction)
|
||||
/// </summary>
|
||||
[ApiController]
|
||||
[Route("api/pdf/zugferd")]
|
||||
[Produces("application/json")]
|
||||
public class ZugferdController(IMediator mediator) : ControllerBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Checks if a PDF contains ZUGFeRD XML attachment.
|
||||
/// Supports multipart/form-data file upload.
|
||||
/// </summary>
|
||||
/// <param name="file">The PDF file to check for ZUGFeRD</param>
|
||||
/// <param name="cancellationToken">Cancellation token</param>
|
||||
/// <returns>ZUGFeRD check result with metadata</returns>
|
||||
/// <response code="200">PDF successfully checked - returns ZUGFeRD status</response>
|
||||
/// <response code="400">Invalid input (file missing, not a PDF, or corrupted)</response>
|
||||
/// <response code="500">Internal server error during PDF processing</response>
|
||||
[HttpPost("has-zugferd")]
|
||||
[Consumes("multipart/form-data")]
|
||||
[ProducesResponseType(typeof(ZugferdCheckResult), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status400BadRequest)]
|
||||
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status500InternalServerError)]
|
||||
public async Task<IActionResult> HasZugferdFromFile(
|
||||
IFormFile file,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
// Use IFormFile stream directly (no intermediate byte[] conversion)
|
||||
using var pdfStream = file.OpenReadStream();
|
||||
|
||||
// Send query to MediatR (ValidationBehavior runs automatically)
|
||||
var query = new HasZugferdQuery { PdfStream = pdfStream };
|
||||
var result = await mediator.Send(query, cancellationToken);
|
||||
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if a PDF contains ZUGFeRD XML attachment.
|
||||
/// Supports Base64-encoded PDF via JSON payload.
|
||||
/// </summary>
|
||||
/// <param name="request">Request containing Base64-encoded PDF</param>
|
||||
/// <param name="cancellationToken">Cancellation token</param>
|
||||
/// <returns>ZUGFeRD check result with metadata</returns>
|
||||
/// <response code="200">PDF successfully checked - returns ZUGFeRD status</response>
|
||||
/// <response code="400">Invalid input (Base64 format error, not a PDF, or corrupted)</response>
|
||||
/// <response code="500">Internal server error during PDF processing</response>
|
||||
[HttpPost("has-zugferd")]
|
||||
[Consumes("application/json")]
|
||||
[ProducesResponseType(typeof(ZugferdCheckResult), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status400BadRequest)]
|
||||
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status500InternalServerError)]
|
||||
public async Task<IActionResult> HasZugferdFromBase64(
|
||||
[FromBody] HasZugferdRequest request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
// Convert Base64 to stream (wrap in try-catch to throw BadRequestException)
|
||||
byte[] pdfBytes;
|
||||
try
|
||||
{
|
||||
pdfBytes = Convert.FromBase64String(request.Base64Pdf);
|
||||
}
|
||||
catch (FormatException ex)
|
||||
{
|
||||
throw new BadRequestException("Invalid Base64 format: " + ex.Message);
|
||||
}
|
||||
|
||||
using var pdfStream = new MemoryStream(pdfBytes);
|
||||
|
||||
// Send query to MediatR (ValidationBehavior runs automatically)
|
||||
var query = new HasZugferdQuery { PdfStream = pdfStream };
|
||||
var result = await mediator.Send(query, cancellationToken);
|
||||
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extracts ZUGFeRD XML from a PDF document.
|
||||
/// Supports multipart/form-data file upload.
|
||||
/// </summary>
|
||||
/// <param name="file">The PDF file to extract ZUGFeRD from</param>
|
||||
/// <param name="asFile">if true, 'file' (returns XML file directly); otherwise output format: 'json' (default, returns metadata + XML content)</param>
|
||||
/// <param name="cancellationToken">Cancellation token</param>
|
||||
/// <returns>ZUGFeRD XML content and metadata (JSON) or XML file (application/xml)</returns>
|
||||
/// <response code="200">ZUGFeRD XML extracted successfully</response>
|
||||
/// <response code="400">Invalid input (file missing, not a PDF, or corrupted)</response>
|
||||
/// <response code="404">PDF contains no ZUGFeRD XML</response>
|
||||
/// <response code="500">Internal server error during PDF processing</response>
|
||||
[HttpPost("extract")]
|
||||
[Consumes("multipart/form-data")]
|
||||
[ProducesResponseType(typeof(ZugferdExtractionResult), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(typeof(FileContentResult), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status400BadRequest)]
|
||||
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)]
|
||||
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status500InternalServerError)]
|
||||
public async Task<IActionResult> ExtractZugferdFromFile(
|
||||
IFormFile file,
|
||||
[FromQuery] bool asFile = true,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
// Use IFormFile stream directly (no intermediate byte[] conversion)
|
||||
using var pdfStream = file.OpenReadStream();
|
||||
|
||||
// Send command to MediatR
|
||||
var command = new ExtractZugferdCommand { PdfStream = pdfStream };
|
||||
var result = await mediator.Send(command, cancellationToken);
|
||||
|
||||
// Return as file or JSON based on format parameter
|
||||
if (asFile)
|
||||
{
|
||||
byte[] xmlBytes = System.Text.Encoding.UTF8.GetBytes(result.XmlContent);
|
||||
return File(xmlBytes, "application/xml", result.FileName);
|
||||
}
|
||||
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extracts ZUGFeRD XML from a PDF document.
|
||||
/// Supports Base64-encoded PDF via JSON payload.
|
||||
/// </summary>
|
||||
/// <param name="request">Request containing Base64-encoded PDF</param>
|
||||
/// <param name="format">Output format: 'json' (default, returns metadata + XML content) or 'file' (returns XML file directly)</param>
|
||||
/// <param name="cancellationToken">Cancellation token</param>
|
||||
/// <returns>ZUGFeRD XML content and metadata (JSON) or XML file (application/xml)</returns>
|
||||
/// <response code="200">ZUGFeRD XML extracted successfully</response>
|
||||
/// <response code="400">Invalid input (Base64 format error, not a PDF, or corrupted)</response>
|
||||
/// <response code="404">PDF contains no ZUGFeRD XML</response>
|
||||
/// <response code="500">Internal server error during PDF processing</response>
|
||||
[HttpPost("extract")]
|
||||
[Consumes("application/json")]
|
||||
[ProducesResponseType(typeof(ZugferdExtractionResult), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(typeof(FileContentResult), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status400BadRequest)]
|
||||
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)]
|
||||
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status500InternalServerError)]
|
||||
public async Task<IActionResult> ExtractZugferdFromBase64(
|
||||
[FromBody] ExtractZugferdRequest request,
|
||||
[FromQuery] string format = "json",
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
// Convert Base64 to stream (wrap in try-catch to throw BadRequestException)
|
||||
byte[] pdfBytes;
|
||||
try
|
||||
{
|
||||
pdfBytes = Convert.FromBase64String(request.Base64Pdf);
|
||||
}
|
||||
catch (FormatException ex)
|
||||
{
|
||||
throw new BadRequestException("Invalid Base64 format: " + ex.Message);
|
||||
}
|
||||
|
||||
using var pdfStream = new MemoryStream(pdfBytes);
|
||||
|
||||
// Send command to MediatR
|
||||
var command = new ExtractZugferdCommand { PdfStream = pdfStream };
|
||||
var result = await mediator.Send(command, cancellationToken);
|
||||
|
||||
// Return as file or JSON based on format parameter
|
||||
if (format.Equals("file", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
byte[] xmlBytes = System.Text.Encoding.UTF8.GetBytes(result.XmlContent);
|
||||
return File(xmlBytes, "application/xml", result.FileName);
|
||||
}
|
||||
|
||||
return Ok(result);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user