diff --git a/DocumentOperator.API/Controllers/PdfAttachmentController.cs b/DocumentOperator.API/Controllers/PdfAttachmentController.cs
index a6d31af..0b03274 100644
--- a/DocumentOperator.API/Controllers/PdfAttachmentController.cs
+++ b/DocumentOperator.API/Controllers/PdfAttachmentController.cs
@@ -1,5 +1,6 @@
using DocumentOperator.Application.CheckPdfAttachments.Queries;
using DocumentOperator.Application.Common.DTOs;
+using DocumentOperator.Application.ExtractPdfAttachments;
using DocumentOperator.Domain.Common.Exceptions;
using MediatR;
using Microsoft.AspNetCore.Http;
@@ -82,6 +83,80 @@ public class PdfAttachmentController(IMediator mediator) : ControllerBase
return Ok(result);
}
+
+ ///
+ /// Extracts all embedded files from a PDF and returns them as a ZIP archive.
+ /// Supports multipart/form-data file upload.
+ ///
+ /// The PDF file to extract attachments from
+ /// Cancellation token
+ /// ZIP archive containing all extracted attachments
+ /// Attachments extracted successfully - returns ZIP file
+ /// Invalid input (file missing, not a PDF, or corrupted)
+ /// PDF contains no attachments
+ /// Internal server error during PDF processing
+ [HttpPost("extract")]
+ [Consumes("multipart/form-data")]
+ [ProducesResponseType(typeof(FileContentResult), StatusCodes.Status200OK)]
+ [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status400BadRequest)]
+ [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)]
+ [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status500InternalServerError)]
+ public async Task ExtractAttachmentsFromFile(
+ IFormFile file,
+ CancellationToken cancellationToken)
+ {
+ // Use IFormFile stream directly (no intermediate byte[] conversion)
+ using var pdfStream = file.OpenReadStream();
+
+ // Send command to MediatR
+ var command = new ExtractPdfAttachmentsCommand { PdfStream = pdfStream };
+ byte[] zipBytes = await mediator.Send(command, cancellationToken);
+
+ // Return ZIP file
+ return File(zipBytes, "application/zip", "attachments.zip");
+ }
+
+ ///
+ /// Extracts all embedded files from a PDF and returns them as a ZIP archive.
+ /// Supports Base64-encoded PDF via JSON payload.
+ ///
+ /// Request containing Base64-encoded PDF
+ /// Cancellation token
+ /// ZIP archive containing all extracted attachments
+ /// Attachments extracted successfully - returns ZIP file
+ /// Invalid input (Base64 format error, not a PDF, or corrupted)
+ /// PDF contains no attachments
+ /// Internal server error during PDF processing
+ [HttpPost("extract")]
+ [Consumes("application/json")]
+ [ProducesResponseType(typeof(FileContentResult), StatusCodes.Status200OK)]
+ [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status400BadRequest)]
+ [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)]
+ [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status500InternalServerError)]
+ public async Task ExtractAttachmentsFromBase64(
+ [FromBody] ExtractPdfAttachmentsRequest 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 command to MediatR
+ var command = new ExtractPdfAttachmentsCommand { PdfStream = pdfStream };
+ byte[] zipBytes = await mediator.Send(command, cancellationToken);
+
+ // Return ZIP file
+ return File(zipBytes, "application/zip", "attachments.zip");
+ }
}
///
@@ -95,3 +170,15 @@ public record CheckPdfAttachmentsRequest
/// JVBERi0xLjQKJeLjz9MKMSAwIG9iago8PC9UeXBlL0NhdGFsb2c...
public string Base64Pdf { get; init; } = string.Empty;
}
+
+///
+/// Request DTO for Base64-encoded PDF attachment extraction
+///
+public record ExtractPdfAttachmentsRequest
+{
+ ///
+ /// PDF document encoded as Base64 string
+ ///
+ /// JVBERi0xLjQKJeLjz9MKMSAwIG9iago8PC9UeXBlL0NhdGFsb2c...
+ public required string Base64Pdf { get; init; }
+}