@@ -4,6 +4,7 @@ using Api.Services.Contracts;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.RateLimiting;
|
||||
using Swashbuckle.AspNetCore.Annotations;
|
||||
using Shared.Models.Responses;
|
||||
|
||||
namespace Api.Controllers;
|
||||
|
||||
@@ -37,8 +38,9 @@ public sealed class CvMatcherController : ControllerBase
|
||||
[HttpPost("upload")]
|
||||
[RequestSizeLimit(8 * 1024 * 1024)]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||
[ProducesResponseType(StatusCodes.Status502BadGateway)]
|
||||
[ProducesResponseType(typeof(ErrorResponse), StatusCodes.Status400BadRequest)]
|
||||
[ProducesResponseType(typeof(ErrorResponse), StatusCodes.Status502BadGateway)]
|
||||
[ProducesResponseType(typeof(ErrorResponse), 499)]
|
||||
[SwaggerOperation(Summary = "Upload CV", Description = "Proxy upload of a CV PDF to the internal cv-matcher-api.")]
|
||||
[SwaggerResponse(StatusCodes.Status200OK, "Upload succeeded")]
|
||||
[SwaggerResponse(StatusCodes.Status400BadRequest, "Missing or invalid input")]
|
||||
@@ -49,7 +51,7 @@ public sealed class CvMatcherController : ControllerBase
|
||||
{
|
||||
if (request.File is null)
|
||||
{
|
||||
return BadRequest(new { error = "Missing CV PDF." });
|
||||
return BadRequest(new ErrorResponse { Error = "Missing CV PDF.", Code = "cv_file_missing" });
|
||||
}
|
||||
|
||||
var cv = request.File;
|
||||
@@ -62,7 +64,7 @@ public sealed class CvMatcherController : ControllerBase
|
||||
if (!verdict.Success)
|
||||
{
|
||||
_logger.LogWarning("Captcha verification failed for CV upload. IP={IP}", userIp);
|
||||
return BadRequest(new { error = "Captcha verification failed." });
|
||||
return BadRequest(new ErrorResponse { Error = "Captcha verification failed.", Code = "captcha_verification_failed" });
|
||||
}
|
||||
|
||||
if (!gdprConsent) throw new InvalidOperationException("GDPR consent is required.");
|
||||
@@ -78,12 +80,12 @@ public sealed class CvMatcherController : ControllerBase
|
||||
catch (OperationCanceledException) when (ct.IsCancellationRequested)
|
||||
{
|
||||
_logger.LogWarning("CV upload proxy request was cancelled by the client.");
|
||||
return StatusCode(499, new { error = "Request cancelled." });
|
||||
return StatusCode(499, new ErrorResponse { Error = "Request cancelled.", Code = "request_cancelled" });
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "CV upload proxy request failed.");
|
||||
return StatusCode(StatusCodes.Status502BadGateway, new { error = "CV matcher API request failed." });
|
||||
return StatusCode(StatusCodes.Status502BadGateway, new ErrorResponse { Error = "CV matcher API request failed.", Code = "upstream_request_failed" });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,8 +96,9 @@ public sealed class CvMatcherController : ControllerBase
|
||||
/// <param name="ct">Cancellation token.</param>
|
||||
[HttpPost("match-job")]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||
[ProducesResponseType(StatusCodes.Status502BadGateway)]
|
||||
[ProducesResponseType(typeof(ErrorResponse), StatusCodes.Status400BadRequest)]
|
||||
[ProducesResponseType(typeof(ErrorResponse), StatusCodes.Status502BadGateway)]
|
||||
[ProducesResponseType(typeof(ErrorResponse), 499)]
|
||||
[SwaggerOperation(Summary = "Match job", Description = "Proxy job matching request to the internal cv-matcher-api.")]
|
||||
[SwaggerResponse(StatusCodes.Status200OK, "Match succeeded")]
|
||||
[SwaggerResponse(StatusCodes.Status400BadRequest, "Invalid request")]
|
||||
@@ -109,7 +112,7 @@ public sealed class CvMatcherController : ControllerBase
|
||||
if (!verdict.Success)
|
||||
{
|
||||
_logger.LogWarning("Captcha verification failed for job match. IP={IP}", userIp);
|
||||
return BadRequest(new { error = "Captcha verification failed." });
|
||||
return BadRequest(new ErrorResponse { Error = "Captcha verification failed.", Code = "captcha_verification_failed" });
|
||||
}
|
||||
|
||||
_logger.LogInformation("Proxying job match request to cv-matcher-api. CvDocumentId={CvDocumentId}, HasJobUrl={HasJobUrl}, HasJobDescription={HasJobDescription}",
|
||||
@@ -122,12 +125,12 @@ public sealed class CvMatcherController : ControllerBase
|
||||
catch (OperationCanceledException) when (ct.IsCancellationRequested)
|
||||
{
|
||||
_logger.LogWarning("Job match proxy request was cancelled by the client.");
|
||||
return StatusCode(499, new { error = "Request cancelled." });
|
||||
return StatusCode(499, new ErrorResponse { Error = "Request cancelled.", Code = "request_cancelled" });
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Job match proxy request failed.");
|
||||
return StatusCode(StatusCodes.Status502BadGateway, new { error = "CV matcher API request failed." });
|
||||
return StatusCode(StatusCodes.Status502BadGateway, new ErrorResponse { Error = "CV matcher API request failed.", Code = "upstream_request_failed" });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user