PortBlog.API/PortBlog.API/Controllers/CvController.cs
Bangara Raju Kottedi 3a7edb23c7 Add JWT, OTP, and caching features
Upgraded projects to .NET 9.0 and added new projects `KBR.Cache`, `KBR.Shared`, and `KBR.Shared.Lite` to the solution. Introduced JWT authentication and OTP handling with new models, services, and configuration options. Updated database schema with new entities `Users` and `RefreshTokens`, and added migrations for schema changes. Implemented caching strategies using `AppDistributedCache` with support for in-memory, SQL Server, and Redis. Enhanced email handling with `MailHelpers` for domain replacement. Updated controllers, repositories, and configuration files to support new features.
2025-11-22 06:52:59 +05:30

271 lines
12 KiB
C#

using Asp.Versioning;
using AutoMapper;
using Microsoft.AspNetCore.Mvc;
using PortBlog.API.Models;
using PortBlog.API.Repositories.Contracts;
using PortBlog.API.Services.Contracts;
namespace PortBlog.API.Controllers
{
[Route("api/v{versions:apiVersion}/cv")]
[ApiController]
[ApiVersion(1)]
public class CvController : ControllerBase
{
private readonly ILogger<CvController> _logger;
private readonly ICandidateRepository _candidateRepository;
private readonly IResumeRepository _resumeRepository;
private readonly IMailRepository _mailRepository;
private readonly IMailService _mailService;
private readonly IMapper _mapper;
public CvController(ILogger<CvController> logger, ICandidateRepository candidateRepository, IResumeRepository resumeRepository, IMailService mailService, IMapper mapper, IMailRepository mailRepository)
{
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_candidateRepository = candidateRepository ?? throw new ArgumentNullException(nameof(candidateRepository));
_resumeRepository = resumeRepository ?? throw new ArgumentNullException(nameof(resumeRepository));
_mailRepository = mailRepository;
_mailService = mailService;
_mapper = mapper;
}
/// <summary>
/// Get CV details of the candidate by candidateid.
/// </summary>
/// <param name="candidateId">The id of the candidate whose cv to get</param>
/// <returns>CV details of the candidate</returns>
/// <response code="200">Returns the requested cv of the candidate</response>
[HttpGet("{candidateId}")]
[Obsolete]
[ApiVersion(0.1, Deprecated = true)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
[ProducesResponseType(StatusCodes.Status200OK)]
public async Task<ActionResult<CvDto>> Get(int candidateId)
{
try
{
if (!await _candidateRepository.CandidateExistAsync(candidateId))
{
_logger.LogInformation($"Candidate with id {candidateId} wasn't found when accessing cv details.");
return NotFound();
}
var latestResumeForCandidate = await _resumeRepository.GetLatestResumeForCandidateAsync(candidateId, true);
return Ok(_mapper.Map<CvDto>(latestResumeForCandidate));
}
catch (Exception ex)
{
_logger.LogCritical($"Exception while getting Cv details for the candidate with id {candidateId}.", ex);
return StatusCode(500, "A problem happened while handling your request.");
}
}
/// <summary>
/// Get hobbies of the candidate by candidateid
/// </summary>
/// <param name="candidateId">The id of the candidate whose hobbies to get</param>
/// <returns>Hobbies of the candidate</returns>
/// <response code="200">Returns the requested hobbies of the candidate</response>
[HttpGet("GetHobbies/{candidateId}")]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
[ProducesResponseType(StatusCodes.Status200OK)]
public async Task<ActionResult<AboutDto>> GetHobbies(int candidateId)
{
try
{
if (!await _candidateRepository.CandidateExistAsync(candidateId))
{
_logger.LogInformation($"Candidate with id {candidateId} wasn't found when fetching about details.");
return NotFound();
}
var aboutDetails = await _resumeRepository.GetHobbiesAsync(candidateId);
return Ok(_mapper.Map<AboutDto>(aboutDetails));
}
catch (Exception ex)
{
_logger.LogCritical($"Exception while getting about details for the candidate with id {candidateId}.", ex);
return StatusCode(500, "A problem happened while handling your request.");
}
}
/// <summary>
/// Get Candidate details with social links by candidateid
/// </summary>
/// <param name="candidateId">The id of the candidate whose detials to get with social links</param>
/// <returns>Candidate details with sociallinks</returns>
/// <response code="200">Returns the requested candidate details with social links</response>
[HttpGet("GetCandidateWithSocialLinks/{candidateId}")]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
[ProducesResponseType(StatusCodes.Status200OK)]
public async Task<ActionResult<CandidateSocialLinksDto>> GetContact(int candidateId)
{
try
{
if (!await _candidateRepository.CandidateExistAsync(candidateId))
{
_logger.LogInformation($"Candidate with id {candidateId} wasn't found when fetching candidate with social links.");
return NotFound();
}
var contact = await _resumeRepository.GetCandidateWithSocialLinksAsync(candidateId);
return Ok(_mapper.Map<CandidateSocialLinksDto>(contact));
}
catch (Exception ex)
{
_logger.LogCritical($"Exception while getting contact for the candidate with social links with id {candidateId}.", ex);
return StatusCode(500, "A problem happened while handling your request.");
}
}
/// <summary>
/// Get Candidate resume by candidateid
/// </summary>
/// <param name="candidateId">The id of the candidate whose resume to get</param>
/// <returns>Candidate resume</returns>
/// <response code="200">Returns the requested candidate resume</response>
[HttpGet("GetResume/{candidateId}")]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
[ProducesResponseType(StatusCodes.Status200OK)]
public async Task<ActionResult<ResumeDto>> GetResume(int candidateId)
{
try
{
if (!await _candidateRepository.CandidateExistAsync(candidateId))
{
_logger.LogInformation($"Candidate with id {candidateId} wasn't found when fetching resume.");
return NotFound();
}
var resume = await _resumeRepository.GetResumeAsync(candidateId);
return Ok(_mapper.Map<ResumeDto>(resume));
}
catch (Exception ex)
{
_logger.LogCritical($"Exception while getting resume for the candidate with id {candidateId}.", ex);
return StatusCode(500, "A problem happened while handling your request.");
}
}
/// <summary>
/// Get Candidate projects by candidateid
/// </summary>
/// <param name="candidateId">The id of the candidate whose projects to get</param>
/// <returns>Candidate projects</returns>
/// <response code="200">Returns the requested candidate projects</response>
[HttpGet("GetProjects/{candidateId}")]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
[ProducesResponseType(StatusCodes.Status200OK)]
public async Task<ActionResult<ProjectsDto>> GetProjects(int candidateId)
{
try
{
if (!await _candidateRepository.CandidateExistAsync(candidateId))
{
_logger.LogInformation($"Candidate with id {candidateId} wasn't found when fetching projects.");
return NotFound();
}
var projects = await _resumeRepository.GetProjectsAsync(candidateId);
return Ok(_mapper.Map<ProjectsDto>(projects));
}
catch (Exception ex)
{
_logger.LogCritical($"Exception while getting projects for the candidate with id {candidateId}.", ex);
return StatusCode(500, "A problem happened while handling your request.");
}
}
/// <summary>
/// Get Candidate blog with posts by candidateid
/// </summary>
/// <param name="candidateId">The id of the candidate whose blog with posts to get</param>
/// <returns>Candidate blog with posts</returns>
/// <response code="200">Returns the requested candidate blog with posts</response>
[HttpGet("GetBlog/{candidateId}")]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
[ProducesResponseType(StatusCodes.Status200OK)]
public async Task<ActionResult<BlogDto>> GetBlog(int candidateId)
{
try
{
if (!await _candidateRepository.CandidateExistAsync(candidateId))
{
_logger.LogInformation($"Candidate with id {candidateId} wasn't found when fetching projects.");
return NotFound();
}
var blog = await _resumeRepository.GetBlogAsync(candidateId);
return Ok(_mapper.Map<BlogDto>(blog));
}
catch (Exception ex)
{
_logger.LogCritical($"Exception while getting projects for the candidate with id {candidateId}.", ex);
return StatusCode(500, "A problem happened while handling your request.");
}
}
/// <summary>
/// Send Message through email
/// </summary>
/// <param name="candidateId">The id of the candidate to whom the message should be sent</param>
/// <param name="message">Details of the Message to send to the candidate</param>
/// <returns>Returns the status code</returns>
/// <response code="204">Returns nothing</response>
[HttpPost("SendMessage/{candidateId}")]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
[ProducesResponseType(StatusCodes.Status204NoContent)]
public async Task<ActionResult<bool>> SendMessage(int candidateId, [FromBody] MessageDto message)
{
try
{
var candidate = await _candidateRepository.GetCandidateAsync(candidateId);
if (candidate == null)
{
_logger.LogInformation($"Candidate with id {candidateId} wasn't found when fetching projects.");
return NotFound();
}
var candidateDto = _mapper.Map<CandidateDto>(candidate);
var messageSendDto = _mapper.Map<MessageSendDto>(message);
messageSendDto.ToEmail = candidateDto.Email;
messageSendDto.Name = candidateDto.DisplayName;
messageSendDto.CandidateId = candidateDto.CandidateId;
await _mailService.SendAsync(messageSendDto);
return Ok(true);
}
catch (Exception ex)
{
_logger.LogCritical($"Exception while sending message from {message.Name}.", ex);
return StatusCode(500, "A problem happened while handling your request.");
}
}
}
}