Comments
This commit is contained in:
@@ -6,6 +6,7 @@ using Microsoft.AspNetCore.RateLimiting;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Models.Settings;
|
||||
using Models.Requests;
|
||||
using Swashbuckle.AspNetCore.Annotations;
|
||||
|
||||
namespace Api.Controllers
|
||||
{
|
||||
@@ -42,6 +43,13 @@ namespace Api.Controllers
|
||||
/// </returns>
|
||||
[HttpPost]
|
||||
[EnableRateLimiting("contact")]
|
||||
[SwaggerOperation(Summary = "Send contact message", Description = "Validates captcha and sends a contact message using the configured email sender.")]
|
||||
[SwaggerResponse(StatusCodes.Status200OK, "Contact message sent")]
|
||||
[SwaggerResponse(StatusCodes.Status400BadRequest, "Invalid request or captcha verification failed")]
|
||||
[SwaggerResponse(StatusCodes.Status500InternalServerError, "Contact message could not be sent due to server error")]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
|
||||
public async Task<IActionResult> Send([FromBody] ContactRequest req, CancellationToken ct)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
@@ -76,6 +84,13 @@ namespace Api.Controllers
|
||||
/// </returns>
|
||||
[HttpPost("subscribe")]
|
||||
[EnableRateLimiting("contact")]
|
||||
[SwaggerOperation(Summary = "Subscribe email", Description = "Validates captcha and subscribes an email address to the mailing list.")]
|
||||
[SwaggerResponse(StatusCodes.Status200OK, "Subscription succeeded")]
|
||||
[SwaggerResponse(StatusCodes.Status400BadRequest, "Invalid request or captcha verification failed")]
|
||||
[SwaggerResponse(StatusCodes.Status500InternalServerError, "Subscription failed due to server error")]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
|
||||
public async Task<IActionResult> Subscribe([FromBody] SubscribeRequest req, CancellationToken ct)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
|
||||
@@ -5,6 +5,7 @@ using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.StaticFiles;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Microsoft.Net.Http.Headers;
|
||||
using Swashbuckle.AspNetCore.Annotations;
|
||||
|
||||
namespace Api.Controllers
|
||||
{
|
||||
@@ -47,10 +48,19 @@ namespace Api.Controllers
|
||||
/// <response code="404">File not found</response>
|
||||
/// <response code="416">Requested range not satisfiable</response>
|
||||
[HttpGet("{fileName?}")]
|
||||
[SwaggerOperation(Summary = "Download file", Description = "Downloads a file with support for full and ranged (resumable) transfers.")]
|
||||
[SwaggerResponse(StatusCodes.Status200OK, "Full file content returned")]
|
||||
[SwaggerResponse(StatusCodes.Status206PartialContent, "Partial file content returned for a range request")]
|
||||
[SwaggerResponse(StatusCodes.Status400BadRequest, "No file name provided and no default configured")]
|
||||
[SwaggerResponse(StatusCodes.Status404NotFound, "Requested file was not found")]
|
||||
[SwaggerResponse(StatusCodes.Status416RangeNotSatisfiable, "Requested byte range is invalid")]
|
||||
[SwaggerResponse(StatusCodes.Status500InternalServerError, "Unexpected server error while downloading")]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status206PartialContent)]
|
||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
[ProducesResponseType(StatusCodes.Status416RangeNotSatisfiable)]
|
||||
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
|
||||
public async Task<IActionResult> DownloadFile(string? fileName = null)
|
||||
{
|
||||
try
|
||||
|
||||
@@ -2,6 +2,7 @@ using Models.Settings;
|
||||
using Microsoft.AspNetCore.Cors;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Swashbuckle.AspNetCore.Annotations;
|
||||
|
||||
namespace Api.Controllers
|
||||
{
|
||||
@@ -29,6 +30,9 @@ namespace Api.Controllers
|
||||
/// </summary>
|
||||
/// <returns>200 OK with the Tag Manager ID as a string.</returns>
|
||||
[HttpGet("tagmanager")]
|
||||
[SwaggerOperation(Summary = "Get Google Tag Manager ID", Description = "Returns the Google Tag Manager ID configured for frontend analytics.")]
|
||||
[SwaggerResponse(StatusCodes.Status200OK, "Tag Manager ID returned")]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
public async Task<IActionResult> GetTagManagerId(CancellationToken ct)
|
||||
{
|
||||
return Ok(_googleSettings.TagManagerId);
|
||||
@@ -41,6 +45,9 @@ namespace Api.Controllers
|
||||
/// </summary>
|
||||
/// <returns>200 OK with the maps API key as a string.</returns>
|
||||
[HttpGet("maps")]
|
||||
[SwaggerOperation(Summary = "Get Google Maps key", Description = "Returns the Google Maps API key configured for frontend map features.")]
|
||||
[SwaggerResponse(StatusCodes.Status200OK, "Maps API key returned")]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
public async Task<IActionResult> GetMapKey(CancellationToken ct)
|
||||
{
|
||||
return Ok(_googleSettings.MapKey);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Microsoft.AspNetCore.Cors;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Swashbuckle.AspNetCore.Annotations;
|
||||
|
||||
namespace Api.Controllers
|
||||
{
|
||||
@@ -22,6 +23,9 @@ namespace Api.Controllers
|
||||
/// </returns>
|
||||
// GET api/health/live
|
||||
[HttpGet("live")]
|
||||
[SwaggerOperation(Summary = "Liveness probe", Description = "Returns whether the API process is alive.")]
|
||||
[SwaggerResponse(StatusCodes.Status200OK, "Service is alive")]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
public IActionResult Live() => Ok(new { status = "alive" });
|
||||
|
||||
/// <summary>
|
||||
@@ -33,6 +37,9 @@ namespace Api.Controllers
|
||||
/// </returns>
|
||||
// GET api/health
|
||||
[HttpGet]
|
||||
[SwaggerOperation(Summary = "Health check", Description = "Returns overall health status and current UTC time.")]
|
||||
[SwaggerResponse(StatusCodes.Status200OK, "Health check succeeded")]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
public IActionResult Health() => Ok(new { status = "ok", time = DateTimeOffset.UtcNow });
|
||||
|
||||
/// <summary>
|
||||
@@ -43,6 +50,9 @@ namespace Api.Controllers
|
||||
/// <returns>200 OK with the same JSON payload provided in the request body.</returns>
|
||||
// POST api/health/echo
|
||||
[HttpPost("echo")]
|
||||
[SwaggerOperation(Summary = "Echo payload", Description = "Returns the same JSON payload received in the request body.")]
|
||||
[SwaggerResponse(StatusCodes.Status200OK, "Payload echoed successfully")]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
public IActionResult Echo(object payload) => Ok(payload);
|
||||
|
||||
/// <summary>
|
||||
@@ -55,6 +65,11 @@ namespace Api.Controllers
|
||||
/// </returns>
|
||||
// GET api/health/ready
|
||||
[HttpGet("ready")]
|
||||
[SwaggerOperation(Summary = "Readiness probe", Description = "Returns whether the service is ready to accept traffic.")]
|
||||
[SwaggerResponse(StatusCodes.Status200OK, "Service is ready")]
|
||||
[SwaggerResponse(StatusCodes.Status503ServiceUnavailable, "Service is not ready")]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status503ServiceUnavailable)]
|
||||
public IActionResult Ready()
|
||||
{
|
||||
var ready = true;
|
||||
|
||||
@@ -3,6 +3,7 @@ using Api.Services.Contracts;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using CvMatcher.Models.Responses;
|
||||
using Shared.Models.Requests;
|
||||
using Swashbuckle.AspNetCore.Annotations;
|
||||
|
||||
namespace Api.Controllers;
|
||||
|
||||
@@ -21,6 +22,11 @@ public sealed class CvController : ControllerBase
|
||||
|
||||
[HttpPost("upload")]
|
||||
[RequestSizeLimit(10 * 1024 * 1024)]
|
||||
[SwaggerOperation(Summary = "Upload CV document", Description = "Uploads a CV PDF and indexes it for matching.")]
|
||||
[SwaggerResponse(StatusCodes.Status200OK, "CV uploaded and indexed successfully")]
|
||||
[SwaggerResponse(StatusCodes.Status400BadRequest, "Invalid upload request")]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||
public async Task<ActionResult<CvUploadResponse>> Upload([FromForm] UploadFileRequest request, CancellationToken ct)
|
||||
{
|
||||
try
|
||||
@@ -39,6 +45,11 @@ public sealed class CvController : ControllerBase
|
||||
}
|
||||
|
||||
[HttpPost("find-jobs")]
|
||||
[SwaggerOperation(Summary = "Find matching jobs", Description = "Finds top matching jobs for a previously uploaded CV document.")]
|
||||
[SwaggerResponse(StatusCodes.Status200OK, "Matching jobs returned")]
|
||||
[SwaggerResponse(StatusCodes.Status400BadRequest, "Invalid find jobs request")]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||
public async Task<ActionResult<FindJobsResponse>> FindJobs([FromBody] FindJobsRequest request, CancellationToken ct)
|
||||
{
|
||||
try
|
||||
@@ -56,6 +67,11 @@ public sealed class CvController : ControllerBase
|
||||
}
|
||||
|
||||
[HttpPost("match-job")]
|
||||
[SwaggerOperation(Summary = "Match CV to one job", Description = "Computes detailed match analysis between a CV and a single job description or URL.")]
|
||||
[SwaggerResponse(StatusCodes.Status200OK, "Job match computed successfully")]
|
||||
[SwaggerResponse(StatusCodes.Status400BadRequest, "Invalid match job request")]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||
public async Task<ActionResult<JobMatchResponse>> MatchJob([FromBody] MatchJobRequest request, CancellationToken ct)
|
||||
{
|
||||
try
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Swashbuckle.AspNetCore.Annotations;
|
||||
|
||||
namespace Api.Controllers
|
||||
{
|
||||
@@ -19,6 +20,9 @@ namespace Api.Controllers
|
||||
/// </returns>
|
||||
// GET api/health/live
|
||||
[HttpGet("live")]
|
||||
[SwaggerOperation(Summary = "Liveness probe", Description = "Returns whether the API process is alive.")]
|
||||
[SwaggerResponse(StatusCodes.Status200OK, "Service is alive")]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
public IActionResult Live() => Ok(new { status = "alive" });
|
||||
|
||||
/// <summary>
|
||||
@@ -30,6 +34,9 @@ namespace Api.Controllers
|
||||
/// </returns>
|
||||
// GET api/health
|
||||
[HttpGet]
|
||||
[SwaggerOperation(Summary = "Health check", Description = "Returns overall health status and current UTC time.")]
|
||||
[SwaggerResponse(StatusCodes.Status200OK, "Health check succeeded")]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
public IActionResult Health() => Ok(new { status = "ok", time = DateTimeOffset.UtcNow });
|
||||
|
||||
/// <summary>
|
||||
@@ -40,6 +47,9 @@ namespace Api.Controllers
|
||||
/// <returns>200 OK with the same JSON payload provided in the request body.</returns>
|
||||
// POST api/health/echo
|
||||
[HttpPost("echo")]
|
||||
[SwaggerOperation(Summary = "Echo payload", Description = "Returns the same JSON payload received in the request body.")]
|
||||
[SwaggerResponse(StatusCodes.Status200OK, "Payload echoed successfully")]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
public IActionResult Echo(object payload) => Ok(payload);
|
||||
|
||||
/// <summary>
|
||||
@@ -52,6 +62,11 @@ namespace Api.Controllers
|
||||
/// </returns>
|
||||
// GET api/health/ready
|
||||
[HttpGet("ready")]
|
||||
[SwaggerOperation(Summary = "Readiness probe", Description = "Returns whether the service is ready to accept traffic.")]
|
||||
[SwaggerResponse(StatusCodes.Status200OK, "Service is ready")]
|
||||
[SwaggerResponse(StatusCodes.Status503ServiceUnavailable, "Service is not ready")]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status503ServiceUnavailable)]
|
||||
public IActionResult Ready()
|
||||
{
|
||||
var ready = true;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Swashbuckle.AspNetCore.Annotations;
|
||||
|
||||
namespace Api.Controllers
|
||||
{
|
||||
@@ -19,6 +20,9 @@ namespace Api.Controllers
|
||||
/// </returns>
|
||||
// GET api/health/live
|
||||
[HttpGet("live")]
|
||||
[SwaggerOperation(Summary = "Liveness probe", Description = "Returns whether the API process is alive.")]
|
||||
[SwaggerResponse(StatusCodes.Status200OK, "Service is alive")]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
public IActionResult Live() => Ok(new { status = "alive" });
|
||||
|
||||
/// <summary>
|
||||
@@ -30,6 +34,9 @@ namespace Api.Controllers
|
||||
/// </returns>
|
||||
// GET api/health
|
||||
[HttpGet]
|
||||
[SwaggerOperation(Summary = "Health check", Description = "Returns overall health status and current UTC time.")]
|
||||
[SwaggerResponse(StatusCodes.Status200OK, "Health check succeeded")]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
public IActionResult Health() => Ok(new { status = "ok", time = DateTimeOffset.UtcNow });
|
||||
|
||||
/// <summary>
|
||||
@@ -40,6 +47,9 @@ namespace Api.Controllers
|
||||
/// <returns>200 OK with the same JSON payload provided in the request body.</returns>
|
||||
// POST api/health/echo
|
||||
[HttpPost("echo")]
|
||||
[SwaggerOperation(Summary = "Echo payload", Description = "Returns the same JSON payload received in the request body.")]
|
||||
[SwaggerResponse(StatusCodes.Status200OK, "Payload echoed successfully")]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
public IActionResult Echo(object payload) => Ok(payload);
|
||||
|
||||
/// <summary>
|
||||
@@ -52,6 +62,11 @@ namespace Api.Controllers
|
||||
/// </returns>
|
||||
// GET api/health/ready
|
||||
[HttpGet("ready")]
|
||||
[SwaggerOperation(Summary = "Readiness probe", Description = "Returns whether the service is ready to accept traffic.")]
|
||||
[SwaggerResponse(StatusCodes.Status200OK, "Service is ready")]
|
||||
[SwaggerResponse(StatusCodes.Status503ServiceUnavailable, "Service is not ready")]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status503ServiceUnavailable)]
|
||||
public IActionResult Ready()
|
||||
{
|
||||
var ready = true;
|
||||
|
||||
@@ -2,6 +2,7 @@ using Microsoft.AspNetCore.Mvc;
|
||||
using Api.Services.Contracts;
|
||||
using Rag.Models.Requests;
|
||||
using Rag.Models.Responses;
|
||||
using Swashbuckle.AspNetCore.Annotations;
|
||||
|
||||
namespace Api.Controllers;
|
||||
|
||||
@@ -20,6 +21,11 @@ public sealed class RagController : ControllerBase
|
||||
|
||||
[HttpPost("documents")]
|
||||
[RequestSizeLimit(10 * 1024 * 1024)]
|
||||
[SwaggerOperation(Summary = "Index document (multipart)", Description = "Indexes a PDF file or raw text document using multipart/form-data payload.")]
|
||||
[SwaggerResponse(StatusCodes.Status200OK, "Document indexed successfully")]
|
||||
[SwaggerResponse(StatusCodes.Status400BadRequest, "Invalid indexing request")]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||
public async Task<ActionResult<IndexDocumentResponse>> IndexDocument(
|
||||
[FromForm] IndexDocumentUploadRequest request,
|
||||
CancellationToken ct)
|
||||
@@ -56,6 +62,11 @@ public sealed class RagController : ControllerBase
|
||||
}
|
||||
|
||||
[HttpPost("documents/json")]
|
||||
[SwaggerOperation(Summary = "Index document (JSON)", Description = "Indexes a text document sent as JSON.")]
|
||||
[SwaggerResponse(StatusCodes.Status200OK, "JSON document indexed successfully")]
|
||||
[SwaggerResponse(StatusCodes.Status400BadRequest, "Invalid JSON indexing request")]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||
public async Task<ActionResult<IndexDocumentResponse>> IndexJsonDocument([FromBody] IndexDocumentRequest request, CancellationToken ct)
|
||||
{
|
||||
try
|
||||
@@ -75,6 +86,11 @@ public sealed class RagController : ControllerBase
|
||||
}
|
||||
|
||||
[HttpPost("search")]
|
||||
[SwaggerOperation(Summary = "Semantic search", Description = "Performs semantic retrieval over indexed documents.")]
|
||||
[SwaggerResponse(StatusCodes.Status200OK, "Search results returned")]
|
||||
[SwaggerResponse(StatusCodes.Status400BadRequest, "Invalid search request")]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||
public async Task<ActionResult<SearchResponse>> Search([FromBody] SearchRequest request, CancellationToken ct)
|
||||
{
|
||||
try
|
||||
@@ -93,6 +109,11 @@ public sealed class RagController : ControllerBase
|
||||
}
|
||||
|
||||
[HttpGet("documents/{id}")]
|
||||
[SwaggerOperation(Summary = "Get document details", Description = "Returns indexed document details for the provided document id.")]
|
||||
[SwaggerResponse(StatusCodes.Status200OK, "Document details returned")]
|
||||
[SwaggerResponse(StatusCodes.Status404NotFound, "Document was not found")]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public async Task<ActionResult<RagDocumentDetailsResponse>> GetDocument(string id, CancellationToken ct)
|
||||
{
|
||||
_logger.LogInformation("Get document request received. DocumentId={DocumentId}", id);
|
||||
|
||||
Reference in New Issue
Block a user