diff --git a/PortBlog.API/Controllers/CvController.cs b/PortBlog.API/Controllers/CvController.cs index 1a93a89..ace7c6f 100644 --- a/PortBlog.API/Controllers/CvController.cs +++ b/PortBlog.API/Controllers/CvController.cs @@ -46,5 +46,120 @@ namespace PortBlog.API.Controllers return StatusCode(500, "A problem happened while handling your request."); } } + + [HttpGet("GetHobbies/{candidateId}")] + public async Task> 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(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."); + } + } + + [HttpGet("GetCandidateWithSocialLinks/{candidateId}")] + public async Task> 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(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."); + } + } + + [HttpGet("GetResume/{candidateId}")] + public async Task> 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(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."); + } + } + + [HttpGet("GetProjects/{candidateId}")] + public async Task> 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(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."); + } + } + + [HttpGet("GetBlog/{candidateId}")] + public async Task> 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(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."); + } + } } } diff --git a/PortBlog.API/Entities/Candidate.cs b/PortBlog.API/Entities/Candidate.cs index 61a2c11..9d9d053 100644 --- a/PortBlog.API/Entities/Candidate.cs +++ b/PortBlog.API/Entities/Candidate.cs @@ -1,6 +1,5 @@ using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; -using System.Diagnostics.Contracts; namespace PortBlog.API.Entities { diff --git a/PortBlog.API/Models/AboutDto.cs b/PortBlog.API/Models/AboutDto.cs new file mode 100644 index 0000000..f04f65f --- /dev/null +++ b/PortBlog.API/Models/AboutDto.cs @@ -0,0 +1,9 @@ +namespace PortBlog.API.Models +{ + public class AboutDto + { + public string About { get; set; } = string.Empty; + + public ICollection Hobbies { get; set; } = new List(); + } +} diff --git a/PortBlog.API/Models/BlogDto.cs b/PortBlog.API/Models/BlogDto.cs index 61abf7e..9df2e39 100644 --- a/PortBlog.API/Models/BlogDto.cs +++ b/PortBlog.API/Models/BlogDto.cs @@ -4,8 +4,6 @@ namespace PortBlog.API.Models { public class BlogDto { - public int BlogId { get; set; } - public string Name { get; set; } = string.Empty; public string? Description { get; set; } = string.Empty; diff --git a/PortBlog.API/Models/CandidateSocialLinksDto.cs b/PortBlog.API/Models/CandidateSocialLinksDto.cs new file mode 100644 index 0000000..248a4af --- /dev/null +++ b/PortBlog.API/Models/CandidateSocialLinksDto.cs @@ -0,0 +1,11 @@ +namespace PortBlog.API.Models +{ + public class CandidateSocialLinksDto + { + public string Title { get; set; } = string.Empty; + + public CandidateDto? Candidate { get; set; } + + public SocialLinksDto? SocialLinks { get; set; } + } +} diff --git a/PortBlog.API/Models/ProjectsDto.cs b/PortBlog.API/Models/ProjectsDto.cs new file mode 100644 index 0000000..b4df49f --- /dev/null +++ b/PortBlog.API/Models/ProjectsDto.cs @@ -0,0 +1,15 @@ +namespace PortBlog.API.Models +{ + public class ProjectsDto + { + public ICollection Projects { get; set; } = new List(); + + public ICollection ProjectsCategories + { + get + { + return Projects.Select(p => p.Category).Distinct().ToList(); + } + } + } +} diff --git a/PortBlog.API/Profiles/ResumeProfile.cs b/PortBlog.API/Profiles/ResumeProfile.cs index d418302..faf35db 100644 --- a/PortBlog.API/Profiles/ResumeProfile.cs +++ b/PortBlog.API/Profiles/ResumeProfile.cs @@ -61,6 +61,9 @@ namespace PortBlog.API.Profiles src => src.MapFrom(src => src.Blog != null ? src.Blog.Posts : new List()) ); CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); } } } diff --git a/PortBlog.API/Program.cs b/PortBlog.API/Program.cs index 1b4b01c..52d1a0a 100644 --- a/PortBlog.API/Program.cs +++ b/PortBlog.API/Program.cs @@ -92,6 +92,7 @@ if (app.Environment.IsDevelopment()) app.UseHttpsRedirection(); + app.UseStaticFiles(new StaticFileOptions() { FileProvider = new PhysicalFileProvider(Path.Combine(Directory.GetCurrentDirectory(), @"Images")), diff --git a/PortBlog.API/Repositories/Contracts/IResumeRepository.cs b/PortBlog.API/Repositories/Contracts/IResumeRepository.cs index 4c0622b..c221769 100644 --- a/PortBlog.API/Repositories/Contracts/IResumeRepository.cs +++ b/PortBlog.API/Repositories/Contracts/IResumeRepository.cs @@ -5,5 +5,15 @@ namespace PortBlog.API.Repositories.Contracts public interface IResumeRepository { Task GetLatestResumeForCandidateAsync(int candidateId, bool includeOtherData = false); + + Task GetHobbiesAsync(int candidateId); + + Task GetResumeAsync(int candidateId); + + Task GetCandidateWithSocialLinksAsync(int candidateId); + + Task GetProjectsAsync(int candidateId); + + Task GetBlogAsync(int candidate); } } diff --git a/PortBlog.API/Repositories/ResumeRepository.cs b/PortBlog.API/Repositories/ResumeRepository.cs index 916646b..534ba9b 100644 --- a/PortBlog.API/Repositories/ResumeRepository.cs +++ b/PortBlog.API/Repositories/ResumeRepository.cs @@ -1,6 +1,7 @@ using Microsoft.EntityFrameworkCore; using PortBlog.API.DbContexts; using PortBlog.API.Entities; +using PortBlog.API.Models; using PortBlog.API.Repositories.Contracts; namespace PortBlog.API.Repositories @@ -35,5 +36,52 @@ namespace PortBlog.API.Repositories return await _cvBlogContext.Resumes.Where(r => r.CandidateId == candidateId).OrderByDescending(r => r.Order).FirstOrDefaultAsync(); } + + public async Task GetHobbiesAsync(int candidateId) + { + return await _cvBlogContext.Resumes + .Include(r => r.Hobbies) + .Where(r => r.CandidateId == candidateId) + .OrderByDescending(r => r.Order).FirstOrDefaultAsync(); + } + + public async Task GetResumeAsync(int candidateId) + { + return await _cvBlogContext.Resumes + .Include(r => r.Academics.OrderByDescending(a => a.StartYear)) + .Include(r => r.Experiences.OrderByDescending(e => e.StartDate)) + .Include(r => r.Skills) + .Where(r => r.CandidateId == candidateId) + .FirstOrDefaultAsync(); + } + + public async Task GetCandidateWithSocialLinksAsync(int candidateId) + { + return await _cvBlogContext.Resumes + .Include(r => r.Candidate) + .Include(r => r.SocialLinks) + .Where(r => r.CandidateId == candidateId) + .FirstOrDefaultAsync(); + } + + public async Task GetProjectsAsync(int candidateId) + { + return await _cvBlogContext.Resumes + .Include(r => r.Projects) + .Where(r => r.CandidateId == candidateId) + .FirstOrDefaultAsync(); + } + + public async Task GetBlogAsync(int candidate) + { + var result = await _cvBlogContext.Resumes + .Include(r => r.SocialLinks) + .ThenInclude(s => s.Blog) + .ThenInclude(b => b.Posts.OrderByDescending(p => p.Likes).Take(5)) + .Where(r => r.CandidateId == candidate) + .FirstOrDefaultAsync(); + + return result?.SocialLinks?.Blog; + } } }