diff --git a/Tsi1.Api/Tsi1.Api/Controllers/TenantController.cs b/Tsi1.Api/Tsi1.Api/Controllers/TenantController.cs new file mode 100644 index 0000000000000000000000000000000000000000..f89bb6beb7a7a425bda20d76669b2315ba465083 --- /dev/null +++ b/Tsi1.Api/Tsi1.Api/Controllers/TenantController.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Generic; +using System.Linq; +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 TenantController : ControllerBase + { + private readonly ITenantService _tenantService; + + public TenantController(ITenantService tenantService) + { + _tenantService = tenantService; + } + + [Authorize(Roles = UserTypes.UdelarAdmin)] + [HttpGet("GetAll")] + public async Task<IActionResult> GetAll() + { + var result = await _tenantService.GetAll(); + + if (result.HasError) + { + return BadRequest(result.Message); + } + + return Ok(result.Data); + } + + [Authorize(Roles = UserTypes.UdelarAdmin)] + [HttpPost("Create")] + public async Task<IActionResult> Create(TenantCreateDto newTenant) + { + var result = await _tenantService.Create(newTenant); + + if (result.HasError) + { + return BadRequest(result.Message); + } + + return Ok(result.Data); + } + } +} diff --git a/Tsi1.Api/Tsi1.Api/Controllers/UserController.cs b/Tsi1.Api/Tsi1.Api/Controllers/UserController.cs index bc4b6fa4028264d7031c91412de327d2f4f1c4d3..a26c7605f61b743c49ccff01a57abfe17befab5c 100644 --- a/Tsi1.Api/Tsi1.Api/Controllers/UserController.cs +++ b/Tsi1.Api/Tsi1.Api/Controllers/UserController.cs @@ -22,19 +22,40 @@ namespace Tsi1.Api.Controllers private readonly IJwtAuthManager _jwtAuthManager; private readonly IUserService _userService; private readonly IUserTypeService _userTypeService; + private readonly ITenantService _tenantService; - public UserController(IJwtAuthManager jwtAuthManager, IUserService userService, IUserTypeService userTypeService) + public UserController(IJwtAuthManager jwtAuthManager, IUserService userService, + IUserTypeService userTypeService, ITenantService tenantService) { _jwtAuthManager = jwtAuthManager; _userService = userService; _userTypeService = userTypeService; + _tenantService = tenantService; } [AllowAnonymous] [HttpPost("Login")] public async Task<IActionResult> Login(LoginRequest request) { - var result = await _userService.Authenticate(request.UserName, request.Password, request.TenantId); + var resultSplit = request.UserName.Split("@"); + + if (resultSplit.Count() != 2) + { + return BadRequest(ErrorMessages.InvalidUsername); + } + + var userName = resultSplit[0]; + + var tenantName = resultSplit[1]; + + var tenantId = await _tenantService.GetByName(tenantName); + + if (tenantId.HasError) + { + return BadRequest(tenantId.Message); + } + + var result = await _userService.Authenticate(userName, request.Password, tenantId.Data); if (result.HasError) { diff --git a/Tsi1.Api/Tsi1.Api/Models/LoginRequest.cs b/Tsi1.Api/Tsi1.Api/Models/LoginRequest.cs index 0ce83cfe5fb8a94cd72d654e67cf93019638fdd8..96e87b18d03e7185430f760fb0a5c9caefe6611f 100644 --- a/Tsi1.Api/Tsi1.Api/Models/LoginRequest.cs +++ b/Tsi1.Api/Tsi1.Api/Models/LoginRequest.cs @@ -16,9 +16,5 @@ namespace Tsi1.Api.Models [Required] [JsonPropertyName("password")] public string Password { get; set; } - - [Required] - [JsonPropertyName("tenantId")] - public int TenantId { get; set; } } } diff --git a/Tsi1.Api/Tsi1.Api/Startup.cs b/Tsi1.Api/Tsi1.Api/Startup.cs index 6d81c782a6874fe01d7d13bd1692e974f6e06fcc..79120833c4a371a113750cacb92f35edfb71abf9 100644 --- a/Tsi1.Api/Tsi1.Api/Startup.cs +++ b/Tsi1.Api/Tsi1.Api/Startup.cs @@ -60,7 +60,8 @@ namespace Tsi1.Api services.AddScoped<ICourseService, CourseService>(); services.AddScoped<IForumService, ForumService>(); services.AddScoped<IPostService, PostService>(); - services.AddScoped<IPostMessageService, PostMessageService>(); + services.AddScoped<IPostMessageService, PostMessageService>(); + services.AddScoped<ITenantService, TenantService>(); services.Configure<MailSettings>(Configuration.GetSection("MailSettings")); services.AddScoped<IEmailService, EmailService>(); diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Dtos/TenantCreateDto.cs b/Tsi1.Api/Tsi1.BusinessLayer/Dtos/TenantCreateDto.cs new file mode 100644 index 0000000000000000000000000000000000000000..1906971794cc8058b47049cbc22f6e4a7ab84dd2 --- /dev/null +++ b/Tsi1.Api/Tsi1.BusinessLayer/Dtos/TenantCreateDto.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Tsi1.BusinessLayer.Dtos +{ + public class TenantCreateDto + { + public string Name { get; set; } + } +} diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Dtos/TenantPreviewDto.cs b/Tsi1.Api/Tsi1.BusinessLayer/Dtos/TenantPreviewDto.cs new file mode 100644 index 0000000000000000000000000000000000000000..74b8300acafec93c16aac87e34da1af457055766 --- /dev/null +++ b/Tsi1.Api/Tsi1.BusinessLayer/Dtos/TenantPreviewDto.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Tsi1.BusinessLayer.Dtos +{ + public class TenantPreviewDto + { + public int Id { get; set; } + + public string Name { get; set; } + } +} diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Helpers/ErrorMessages.cs b/Tsi1.Api/Tsi1.BusinessLayer/Helpers/ErrorMessages.cs index 880795c242b472b8ec7df424f0bc42ac33b789f7..29bacb3defb6998bd6b4fc0be48b0a31c8dc3fa9 100644 --- a/Tsi1.Api/Tsi1.BusinessLayer/Helpers/ErrorMessages.cs +++ b/Tsi1.Api/Tsi1.BusinessLayer/Helpers/ErrorMessages.cs @@ -13,7 +13,8 @@ namespace Tsi1.BusinessLayer.Helpers public const string StudentCourseAlreadyExists = "El estudiante '{0}' ya se encuentra matriculado en el curso '{1}'"; public const string ProffesorDoesNotExist = "El profesor con Id de usuario: '{0}' no existe"; public const string ProfessorCourseAlreadyExists = "El profesor '{0}' ya es docente del curso '{1}'"; - + public const string InvalidUsername = "El nombre de usuario debe ser de la forma: 'usuario@facultad'"; + public const string ForumDoesNotExist = "El foro con id '{0}' no existe"; public const string DuplicateForumName = "Ya existe un foro con nombre '{0}'"; @@ -29,6 +30,9 @@ namespace Tsi1.BusinessLayer.Helpers public const string CourseDoesNotExist = "El curso '{0}' no existe"; public const string DuplicateCourseName = "Ya existe un curso con nombre '{0}'"; - + + public const string TenantDoesNotExist = "La Facultad '{0}' no existe"; + public const string DuplicateTenantName = "Ya existe una Facultad con nombre '{0}'"; + } } diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Helpers/MappingProfile.cs b/Tsi1.Api/Tsi1.BusinessLayer/Helpers/MappingProfile.cs index 8fab13c1e816f8afb5cbf38d9981684b7555ab7b..c00cf1abd7fef1ab43d08a0a6f98a8d3e7ba756c 100644 --- a/Tsi1.Api/Tsi1.BusinessLayer/Helpers/MappingProfile.cs +++ b/Tsi1.Api/Tsi1.BusinessLayer/Helpers/MappingProfile.cs @@ -26,8 +26,9 @@ namespace Tsi1.BusinessLayer.Helpers CreateMap<Professor, ProfessorPreviewDto>(); CreateMap<Course, CourseCreateDto>(); CreateMap<Course, CoursePreviewDto>(); + CreateMap<Tenant, TenantPreviewDto>(); + CreateMap<Tenant, TenantCreateDto>(); - CreateMap<ForumCreateDto, Forum>(); CreateMap<ForumPreviewDto, Forum>(); CreateMap<PostCreateDto, Post>(); @@ -41,7 +42,9 @@ namespace Tsi1.BusinessLayer.Helpers CreateMap<StudentPreviewDto, Student>(); CreateMap<ProfessorPreviewDto, Professor>(); CreateMap<CourseCreateDto, Course>(); - CreateMap<CoursePreviewDto, Course>(); + CreateMap<CoursePreviewDto, Course>(); + CreateMap<TenantPreviewDto, Tenant>(); + CreateMap<TenantCreateDto, Tenant>(); } } } diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Helpers/UserTypes.cs b/Tsi1.Api/Tsi1.BusinessLayer/Helpers/UserTypes.cs index 9fb3b0e8bfd691ed0833bde757acb92626676838..d57a241d16e176b62ab7bdd51b1416cb8b0d42bb 100644 --- a/Tsi1.Api/Tsi1.BusinessLayer/Helpers/UserTypes.cs +++ b/Tsi1.Api/Tsi1.BusinessLayer/Helpers/UserTypes.cs @@ -9,5 +9,6 @@ namespace Tsi1.BusinessLayer.Helpers public const string FacultyAdmin = nameof(FacultyAdmin); public const string Professor = nameof(Professor); public const string Student = nameof(Student); + public const string UdelarAdmin = nameof(UdelarAdmin); } } diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Interfaces/ITenantService.cs b/Tsi1.Api/Tsi1.BusinessLayer/Interfaces/ITenantService.cs new file mode 100644 index 0000000000000000000000000000000000000000..cbdce15a668d89cf3f0459d98d700a618f959675 --- /dev/null +++ b/Tsi1.Api/Tsi1.BusinessLayer/Interfaces/ITenantService.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 ITenantService + { + Task<ServiceResult<int>> GetByName(string tenantName); + + Task<ServiceResult<List<TenantPreviewDto>>> GetAll(); + + Task<ServiceResult<TenantPreviewDto>> Create(TenantCreateDto newTenant); + + //Task<ServiceResult<TenantPreviewDto>> CreateUdelarAdmin(TenantCreateDto newTenant); + } +} diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Services/TenantService.cs b/Tsi1.Api/Tsi1.BusinessLayer/Services/TenantService.cs new file mode 100644 index 0000000000000000000000000000000000000000..fef180d5f1efd31df55b46ce72537a199c10f346 --- /dev/null +++ b/Tsi1.Api/Tsi1.BusinessLayer/Services/TenantService.cs @@ -0,0 +1,83 @@ +using AutoMapper; +using Microsoft.EntityFrameworkCore; +using System; +using System.Collections.Generic; +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 TenantService : ITenantService + { + private readonly Tsi1Context _context; + + private readonly IMapper _mapper; + + public TenantService(Tsi1Context context, IMapper mapper) + { + _context = context; + _mapper = mapper; + } + + public async Task<ServiceResult<List<TenantPreviewDto>>> GetAll() + { + var result = new ServiceResult<List<TenantPreviewDto>>(); + + var tenants = await _context.Tenants.ToListAsync(); + + var tenantsDto = _mapper.Map<List<TenantPreviewDto>>(tenants); + + result.Data = tenantsDto; + + return result; + } + + public async Task<ServiceResult<int>> GetByName(string tenantName) + { + var result = new ServiceResult<int>(); + + var tenant = await _context.Tenants + .FirstOrDefaultAsync(x => x.Name == tenantName); + + if (tenant == null) + { + result.HasError = true; + result.Message = string.Format(ErrorMessages.TenantDoesNotExist, tenantName); + return result; + } + + result.Data = tenant.Id; + + return result; + } + + public async Task<ServiceResult<TenantPreviewDto>> Create(TenantCreateDto newTenant) + { + var result = new ServiceResult<TenantPreviewDto>(); + + var tenant = _mapper.Map<Tenant>(newTenant); + _context.Tenants.Add(tenant); + + try + { + await _context.SaveChangesAsync(); + } + catch (DbUpdateException) + { + result.HasError = true; + result.Message = string.Format(ErrorMessages.DuplicateTenantName, newTenant.Name); + return result; + } + + result.Data = _mapper.Map<TenantPreviewDto>(tenant); + + return result; + } + + } +}