From 576b1c238ac25b101673e836a17462eeaa2d7fd0 Mon Sep 17 00:00:00 2001 From: esantangelo <enzo020895@gmail.com> Date: Sun, 15 Nov 2020 15:20:40 -0300 Subject: [PATCH] communication controller and service --- .../Controllers/CommunicationController.cs | 99 +++++++++++++ Tsi1.Api/Tsi1.Api/Startup.cs | 1 + .../Dtos/CommunicationCreateDto.cs | 17 +++ .../Dtos/CommunicationPreviewDto.cs | 13 ++ .../Helpers/ErrorMessages.cs | 3 + .../Helpers/MappingProfile.cs | 4 + .../Interfaces/ICommunicationService.cs | 20 +++ .../Services/CommunicationService.cs | 139 ++++++++++++++++++ 8 files changed, 296 insertions(+) create mode 100644 Tsi1.Api/Tsi1.Api/Controllers/CommunicationController.cs create mode 100644 Tsi1.Api/Tsi1.BusinessLayer/Dtos/CommunicationCreateDto.cs create mode 100644 Tsi1.Api/Tsi1.BusinessLayer/Dtos/CommunicationPreviewDto.cs create mode 100644 Tsi1.Api/Tsi1.BusinessLayer/Interfaces/ICommunicationService.cs create mode 100644 Tsi1.Api/Tsi1.BusinessLayer/Services/CommunicationService.cs diff --git a/Tsi1.Api/Tsi1.Api/Controllers/CommunicationController.cs b/Tsi1.Api/Tsi1.Api/Controllers/CommunicationController.cs new file mode 100644 index 0000000..7cdda5f --- /dev/null +++ b/Tsi1.Api/Tsi1.Api/Controllers/CommunicationController.cs @@ -0,0 +1,99 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Claims; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Tsi1.BusinessLayer.Dtos; +using Tsi1.BusinessLayer.Helpers; +using Tsi1.BusinessLayer.Interfaces; + +namespace Tsi1.Api.Controllers +{ + [Route("api/[controller]")] + [ApiController] + public class CommunicationController : ControllerBase + { + private readonly ICommunicationService _communicationService; + + public CommunicationController(ICommunicationService communicationService) + { + _communicationService = communicationService; + } + + [Authorize(Roles = UserTypes.FacultyAdmin + ", " + UserTypes.UdelarAdmin)] + [HttpPost("CreateCourseCommunication/{courseId}")] + public async Task<IActionResult> CreateCourseCommunication(CommunicationCreateDto newCommunication, int courseId) + { + var tenantId = int.Parse(HttpContext.User.Claims.FirstOrDefault(x => x.Type == "TenantId").Value); + var validationResult = await _communicationService.TenantValidation(tenantId, courseId); + + if (validationResult.HasError) + { + return BadRequest(validationResult.Message); + } + + var result = await _communicationService.Create(newCommunication, courseId); + + if (result.HasError) + { + return BadRequest(result.Message); + } + + return Ok(); + } + + [Authorize(Roles = UserTypes.FacultyAdmin + ", " + UserTypes.UdelarAdmin)] + [HttpPost("CreateTenantCommunication")] + public async Task<IActionResult> CreateTenantCommunication(CommunicationCreateDto newCommunication, int tenantId) + { + var userType = HttpContext.User.Claims.FirstOrDefault(x => x.Type == ClaimTypes.Role).Value; + if (userType == UserTypes.FacultyAdmin) + { + tenantId = int.Parse(HttpContext.User.Claims.FirstOrDefault(x => x.Type == "TenantId").Value); + } + + newCommunication.IsGlobal = true; + var result = await _communicationService.Create(newCommunication, tenantId); + + if (result.HasError) + { + return BadRequest(result.Message); + } + + return Ok(); + } + + [Authorize(Roles = UserTypes.Student)] + [HttpGet("GetMyCommunications")] + public async Task<IActionResult> GetMyCommunications() + { + var userId = int.Parse(HttpContext.User.Claims.FirstOrDefault(x => x.Type == "Id").Value); + + var result = await _communicationService.GetMyCommunications(userId); + + if (result.HasError) + { + return BadRequest(result.Message); + } + + return Ok(result.Data); + } + + [Authorize(Roles = UserTypes.FacultyAdmin + ", " + UserTypes.UdelarAdmin)] + [HttpDelete("Delete/{communicationId}")] + public async Task<IActionResult> Delete(int communicationId) + { + var result = await _communicationService.Delete(communicationId); + + if (result.HasError) + { + return BadRequest(result.Message); + } + + return Ok(); + } + } +} diff --git a/Tsi1.Api/Tsi1.Api/Startup.cs b/Tsi1.Api/Tsi1.Api/Startup.cs index 369da76..d6ded58 100644 --- a/Tsi1.Api/Tsi1.Api/Startup.cs +++ b/Tsi1.Api/Tsi1.Api/Startup.cs @@ -92,6 +92,7 @@ namespace Tsi1.Api services.AddScoped<ISectionItemTypeService, SectionItemTypeService>(); services.AddScoped<IDataLoad, DataLoad>(); services.AddScoped<ISurveyService, SurveyService>(); + services.AddScoped<ICommunicationService, CommunicationService>(); services.Configure<MailSettings>(Configuration.GetSection("MailSettings")); services.AddScoped<IEmailService, EmailService>(); diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Dtos/CommunicationCreateDto.cs b/Tsi1.Api/Tsi1.BusinessLayer/Dtos/CommunicationCreateDto.cs new file mode 100644 index 0000000..24f82ce --- /dev/null +++ b/Tsi1.Api/Tsi1.BusinessLayer/Dtos/CommunicationCreateDto.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Text.Json.Serialization; + +namespace Tsi1.BusinessLayer.Dtos +{ + public class CommunicationCreateDto + { + public string Text { get; set; } + + [JsonIgnore] + public bool IsGlobal { get; set; } + + public DateTime ValidUntil { get; set; } + } +} diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Dtos/CommunicationPreviewDto.cs b/Tsi1.Api/Tsi1.BusinessLayer/Dtos/CommunicationPreviewDto.cs new file mode 100644 index 0000000..6945046 --- /dev/null +++ b/Tsi1.Api/Tsi1.BusinessLayer/Dtos/CommunicationPreviewDto.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Tsi1.BusinessLayer.Dtos +{ + public class CommunicationPreviewDto + { + public int Id { get; set; } + + public string Text { get; set; } + } +} diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Helpers/ErrorMessages.cs b/Tsi1.Api/Tsi1.BusinessLayer/Helpers/ErrorMessages.cs index c61742a..b049c02 100644 --- a/Tsi1.Api/Tsi1.BusinessLayer/Helpers/ErrorMessages.cs +++ b/Tsi1.Api/Tsi1.BusinessLayer/Helpers/ErrorMessages.cs @@ -61,5 +61,8 @@ namespace Tsi1.BusinessLayer.Helpers public const string SurveyHasNoQuestions = "La encuesta no tiene preguntas"; public const string InvalidSurvey = "La encuesta no pertenece a la facultad con id '{0}'"; public const string SurveyResponseAlreadyExist = "El usuario '{0}' ya completo la encuesta '{1}'"; + + public const string CommunicationDoesNotExist = "La comunicación con id '{0}' no existe"; + public const string InvalidTenant = "El usuario no pertenece a la facultad con id '{0}'"; } } diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Helpers/MappingProfile.cs b/Tsi1.Api/Tsi1.BusinessLayer/Helpers/MappingProfile.cs index d7f378c..2793c82 100644 --- a/Tsi1.Api/Tsi1.BusinessLayer/Helpers/MappingProfile.cs +++ b/Tsi1.Api/Tsi1.BusinessLayer/Helpers/MappingProfile.cs @@ -49,6 +49,8 @@ namespace Tsi1.BusinessLayer.Helpers CreateMap<SurveyResponse, SurveyResponseDetailDto>(); CreateMap<SurveyAnswer, SurveyAnswerDetailDto>(); CreateMap<SurveyAnswer, SurveyAnswerCreateDto>(); + CreateMap<Communication, CommunicationCreateDto>(); + CreateMap<Communication, CommunicationPreviewDto>(); CreateMap<ForumCreateDto, Forum>(); CreateMap<ForumPreviewDto, Forum>(); @@ -87,6 +89,8 @@ namespace Tsi1.BusinessLayer.Helpers CreateMap<SurveyResponseDetailDto, SurveyResponse>(); CreateMap<SurveyAnswerDetailDto, SurveyAnswer>(); CreateMap<SurveyAnswerCreateDto, SurveyAnswer>(); + CreateMap<CommunicationCreateDto, Communication>(); + CreateMap<CommunicationPreviewDto, Communication>(); } } } diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Interfaces/ICommunicationService.cs b/Tsi1.Api/Tsi1.BusinessLayer/Interfaces/ICommunicationService.cs new file mode 100644 index 0000000..ce39e10 --- /dev/null +++ b/Tsi1.Api/Tsi1.BusinessLayer/Interfaces/ICommunicationService.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; +using Tsi1.BusinessLayer.Dtos; +using Tsi1.BusinessLayer.Helpers; + +namespace Tsi1.BusinessLayer.Interfaces +{ + public interface ICommunicationService + { + Task<ServiceResult<bool>> Create(CommunicationCreateDto newCommunication, int id); + + Task<ServiceResult<bool>> Delete(int communicationId); + + Task<ServiceResult<List<CommunicationPreviewDto>>> GetMyCommunications(int userId); + + Task<ServiceResult<bool>> TenantValidation(int tenantId, int courseId); + } +} diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Services/CommunicationService.cs b/Tsi1.Api/Tsi1.BusinessLayer/Services/CommunicationService.cs new file mode 100644 index 0000000..9f7e31b --- /dev/null +++ b/Tsi1.Api/Tsi1.BusinessLayer/Services/CommunicationService.cs @@ -0,0 +1,139 @@ +using AutoMapper; +using Microsoft.EntityFrameworkCore; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tsi1.BusinessLayer.Dtos; +using Tsi1.BusinessLayer.Helpers; +using Tsi1.BusinessLayer.Interfaces; +using Tsi1.DataLayer; +using Tsi1.DataLayer.Entities; + +namespace Tsi1.BusinessLayer.Services +{ + public class CommunicationService : ICommunicationService + { + private readonly Tsi1Context _context; + private readonly IMapper _mapper; + + public CommunicationService(Tsi1Context context, IMapper mapper) + { + _context = context; + _mapper = mapper; + } + + public async Task<ServiceResult<bool>> Create(CommunicationCreateDto newCommunication, int id) + { + var result = new ServiceResult<bool>(); + var isGlobal = newCommunication.IsGlobal; + var commmunication = _mapper.Map<Communication>(newCommunication); + + var validationResult = await this.CreateValidation(id, isGlobal, commmunication); + + if (validationResult.HasError) + { + return validationResult; + } + + _context.Communications.Add(commmunication); + + await _context.SaveChangesAsync(); + + return result; + } + + public async Task<ServiceResult<bool>> Delete(int communicationId) + { + var result = new ServiceResult<bool>(); + var commmunication = await _context.Communications.FirstOrDefaultAsync(x => x.Id == communicationId); + + if (commmunication == null) + { + result.HasError = true; + result.AddMessage(string.Format(ErrorMessages.CommunicationDoesNotExist, communicationId)); + return result; + } + + _context.Communications.Remove(commmunication); + await _context.SaveChangesAsync(); + + return result; + } + + public async Task<ServiceResult<List<CommunicationPreviewDto>>> GetMyCommunications(int userId) + { + var result = new ServiceResult<List<CommunicationPreviewDto>>(); + var user = await _context.Users.AsNoTracking().FirstOrDefaultAsync(x => x.Id == userId); + + var courseIds = await _context.StudentCourses + .AsNoTracking() + .Where(x => x.StudentId == user.StudentId) + .Select(x => x.CourseId) + .ToListAsync(); + + var communications = await _context.Communications + .AsNoTracking() + .Include(x => x.Tenant) + .Include(x => x.Course) + .Where(x => (x.Tenant.Id == userId || courseIds.Contains(x.Course.Id)) + && x.ValidUntil >= DateTime.Now) + .ToListAsync(); + + result.Data = _mapper.Map<List<CommunicationPreviewDto>>(communications); + + return result; + } + + public async Task<ServiceResult<bool>> TenantValidation(int tenantId, int courseId) + { + var result = new ServiceResult<bool>(); + + var tenantAdmin = await _context.Tenants.AsNoTracking().FirstOrDefaultAsync(x => x.Name == TenantAdmin.Name); + var course = await _context.Courses.AsNoTracking().FirstOrDefaultAsync(x => x.Id == courseId); + + if (tenantAdmin.Id != tenantId) + { + result.HasError = course.TenantId != tenantId; + result.AddMessage(string.Format(ErrorMessages.InvalidTenant, course.TenantId)); + } + + return result; + } + + private async Task<ServiceResult<bool>> CreateValidation(int id, bool isGlobal, Communication commmunication) + { + var result = new ServiceResult<bool>(); + + if (isGlobal) + { + var tenant = await _context.Tenants.FirstOrDefaultAsync(x => x.Id == id && x.Name != TenantAdmin.Name); + + if (tenant == null) + { + result.HasError = true; + result.AddMessage(string.Format(ErrorMessages.TenantDoesNotExist, id)); + return result; + } + + commmunication.Tenant = tenant; + } + else + { + var course = await _context.Courses.FirstOrDefaultAsync(x => x.Id == id); + + if (course == null) + { + result.HasError = true; + result.AddMessage(string.Format(ErrorMessages.CourseDoesNotExist, id)); + return result; + } + + commmunication.Course = course; + } + + return result; + } + } +} -- GitLab