diff --git a/Tsi1.Api/Tsi1.Api/Controllers/CourseController.cs b/Tsi1.Api/Tsi1.Api/Controllers/CourseController.cs index 3778365e1fe2c75f2b53f505f789767a2e7cfac3..dd4de595a500ee8c7db2d63f7ea44554be2c910b 100644 --- a/Tsi1.Api/Tsi1.Api/Controllers/CourseController.cs +++ b/Tsi1.Api/Tsi1.Api/Controllers/CourseController.cs @@ -16,10 +16,14 @@ namespace Tsi1.Api.Controllers public class CourseController : ControllerBase { private readonly ICourseService _courseService; + private readonly IUserService _userService; + private readonly IBedeliaService _bedeliaService; - public CourseController(ICourseService courseService) + public CourseController(ICourseService courseService, IUserService userService, IBedeliaService bedeliaService) { _courseService = courseService; + _userService = userService; + _bedeliaService = bedeliaService; } [Authorize(Roles = UserTypes.Student + ", " + UserTypes.Professor)] @@ -54,15 +58,20 @@ namespace Tsi1.Api.Controllers return Ok(result.Data); } - [Authorize(Roles = UserTypes.Student)] [HttpPost("Matriculate/{courseId}")] public async Task<IActionResult> Matriculate(int courseId) { var userId = int.Parse(HttpContext.User.Claims.FirstOrDefault(x => x.Type == "Id").Value); + var user = await _userService.GetById(userId); + + var response = await _bedeliaService.IsValidUser(user.Data.Student.IdentityCard); + if (response.HasError) + { + return BadRequest(response.Message); + } var result = await _courseService.Matriculate(userId, courseId); - if (result.HasError) { return BadRequest(result.Message); @@ -245,5 +254,33 @@ namespace Tsi1.Api.Controllers return Ok(result.Data); } + + [Authorize(Roles = UserTypes.Professor)] + [HttpPost("CloseRecord/{courseId}")] + public async Task<IActionResult> CloseRecord(int courseId) + { + var courseResult = await _courseService.GetById(courseId); + if (courseResult.HasError) + { + return BadRequest(courseResult.Message); + } + + var userResult = await _userService.GetUserGrades(courseId); + if (userResult.HasError) + { + return BadRequest(userResult.Message); + } + + var courseName = courseResult.Data.Name; + var userGrades = userResult.Data; + + var result = await _bedeliaService.CloseRecord(courseName, userGrades); + 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 90bca24e58e0280359f8a1a93b2ecf7f173109cb..b1f0216fa2c2df3e3276360b50b8fb778e5b1c82 100644 --- a/Tsi1.Api/Tsi1.Api/Startup.cs +++ b/Tsi1.Api/Tsi1.Api/Startup.cs @@ -46,17 +46,27 @@ namespace Tsi1.Api { string postgreSqlSection; string mongoDbSection; + string bedeliaBaseUrlSection; + if (_env.IsProduction()) { postgreSqlSection = "PostgreSqlCloud"; mongoDbSection = "Tsi1DatabaseSettingsCloud"; + bedeliaBaseUrlSection = "BedeliaBaseUrlCloud"; } else { postgreSqlSection = "PostgreSql"; mongoDbSection = "Tsi1DatabaseSettings"; + bedeliaBaseUrlSection = "BedeliaBaseUrl"; } + var bedeliaBaseUrl = Configuration.GetSection(bedeliaBaseUrlSection).Value; + services.AddHttpClient<IBedeliaService, BedeliaService>(configureClient => + { + configureClient.BaseAddress = new Uri(bedeliaBaseUrl); + }); + services.AddControllers(); services.AddSignalR(); diff --git a/Tsi1.Api/Tsi1.Api/appsettings.json b/Tsi1.Api/Tsi1.Api/appsettings.json index aeffabd1acc0a4a5296e376e85c35a1114d2770e..d77c42f3c0bdefb6c97c4c38fd5163408ae997c3 100644 --- a/Tsi1.Api/Tsi1.Api/appsettings.json +++ b/Tsi1.Api/Tsi1.Api/appsettings.json @@ -28,6 +28,8 @@ "Host": "smtp.gmail.com", "Port": 587 }, + "BedeliaBaseUrl": "http://localhost:55438/", + "BedeliaBaseUrlCloud": "http://tsi-bedelia.web.elasticloud.uy/", "Logging": { "LogLevel": { "Default": "Information", diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Dtos/CloseRecordDto.cs b/Tsi1.Api/Tsi1.BusinessLayer/Dtos/CloseRecordDto.cs new file mode 100644 index 0000000000000000000000000000000000000000..f0964b6f3c0480dd9452a2dd4ba25ef130a7a7b2 --- /dev/null +++ b/Tsi1.Api/Tsi1.BusinessLayer/Dtos/CloseRecordDto.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Tsi1.BusinessLayer.Dtos +{ + public class CloseRecordDto + { + public string CourseName { get; set; } + public List<UserGradeDto> UserGrades { get; set; } + } +} diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Dtos/UserGradeDto.cs b/Tsi1.Api/Tsi1.BusinessLayer/Dtos/UserGradeDto.cs new file mode 100644 index 0000000000000000000000000000000000000000..8018e6035c1f02da0609ef8a71a4bedcef5f4201 --- /dev/null +++ b/Tsi1.Api/Tsi1.BusinessLayer/Dtos/UserGradeDto.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Tsi1.BusinessLayer.Dtos +{ + public class UserGradeDto + { + public string IdentityCard { get; set; } + public int Grade { get; set; } + } +} diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Helpers/ErrorMessages.cs b/Tsi1.Api/Tsi1.BusinessLayer/Helpers/ErrorMessages.cs index b049c0244d6ec63c379544c1c0da7f90a475a6ad..5f59d5b2f4d8329ba59bae16b4b4429063c7020e 100644 --- a/Tsi1.Api/Tsi1.BusinessLayer/Helpers/ErrorMessages.cs +++ b/Tsi1.Api/Tsi1.BusinessLayer/Helpers/ErrorMessages.cs @@ -34,6 +34,7 @@ namespace Tsi1.BusinessLayer.Helpers public const string CourseDoesNotExist = "El curso con id '{0}' no existe"; public const string DuplicateCourseName = "Ya existe un curso con nombre '{0}'"; public const string CourseIsTemplate = "El curso con id '{0}' es un template"; + public const string CourseHasNoStudents = "El curso con id '{0}' no tiene estudiantes"; 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/Interfaces/IBedeliaService.cs b/Tsi1.Api/Tsi1.BusinessLayer/Interfaces/IBedeliaService.cs new file mode 100644 index 0000000000000000000000000000000000000000..88a6f293779d4dd16356078565ec3010a95dfa37 --- /dev/null +++ b/Tsi1.Api/Tsi1.BusinessLayer/Interfaces/IBedeliaService.cs @@ -0,0 +1,16 @@ +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 IBedeliaService + { + Task<ServiceResult<bool>> IsValidUser(string identityCard); + + Task<ServiceResult<bool>> CloseRecord(string courseName, List<UserGradeDto> userGrades); + } +} diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Interfaces/IUserService.cs b/Tsi1.Api/Tsi1.BusinessLayer/Interfaces/IUserService.cs index 1fa99023a8a11832ee567ce57fa10bbdfcf9286a..e3a89207701c5fb213da6b5365f9555bf446afca 100644 --- a/Tsi1.Api/Tsi1.BusinessLayer/Interfaces/IUserService.cs +++ b/Tsi1.Api/Tsi1.BusinessLayer/Interfaces/IUserService.cs @@ -34,5 +34,7 @@ namespace Tsi1.BusinessLayer.Interfaces Task<ServiceResult<List<UserPreviewDto>>> GetProfessors(int tenantId); Task<ServiceResult<List<UserPreviewDto>>> GetAdmins(int tenantId, string userType); + + Task<ServiceResult<List<UserGradeDto>>> GetUserGrades(int courseId); } } diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Services/BedeliaService.cs b/Tsi1.Api/Tsi1.BusinessLayer/Services/BedeliaService.cs new file mode 100644 index 0000000000000000000000000000000000000000..cd7a08a470c3107dcb49d35dbbe0255cbe4e7dae --- /dev/null +++ b/Tsi1.Api/Tsi1.BusinessLayer/Services/BedeliaService.cs @@ -0,0 +1,61 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Net; +using System.Net.Http; +using System.Text; +using System.Threading.Tasks; +using Tsi1.BusinessLayer.Dtos; +using Tsi1.BusinessLayer.Helpers; +using Tsi1.BusinessLayer.Interfaces; + +namespace Tsi1.BusinessLayer.Services +{ + public class BedeliaService : IBedeliaService + { + private readonly HttpClient _httpClient; + + public BedeliaService(HttpClient httpClient) + { + _httpClient = httpClient; + } + + public async Task<ServiceResult<bool>> IsValidUser(string identityCard) + { + var result = new ServiceResult<bool>(); + + var response = await _httpClient.GetAsync($"api/Users/{identityCard}"); + if (response.StatusCode != HttpStatusCode.OK) + { + result.HasError = true; + var errorMessage = await response.Content.ReadAsStringAsync(); + result.AddMessage(errorMessage); + } + + return result; + } + + public async Task<ServiceResult<bool>> CloseRecord(string courseName, List<UserGradeDto> userGrades) + { + var result = new ServiceResult<bool>(); + var closeRecord = new CloseRecordDto() + { + CourseName = courseName, + UserGrades = userGrades + }; + + var jsonInString = JsonConvert.SerializeObject(closeRecord); + var model = new StringContent(jsonInString, Encoding.UTF8, "application/json"); + + var response = await _httpClient.PostAsync("api/Courses/closeRecord", model); + if (response.StatusCode != HttpStatusCode.OK) + { + result.HasError = true; + var errorMessage = await response.Content.ReadAsStringAsync(); + result.AddMessage(errorMessage); + } + + return result; + } + } +} diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Services/UserService.cs b/Tsi1.Api/Tsi1.BusinessLayer/Services/UserService.cs index ca09556ce683038f99c0841051b99a58b7e6cb49..445386e82d56c1f5a4d60a785973aebfb179118e 100644 --- a/Tsi1.Api/Tsi1.BusinessLayer/Services/UserService.cs +++ b/Tsi1.Api/Tsi1.BusinessLayer/Services/UserService.cs @@ -358,5 +358,31 @@ namespace Tsi1.BusinessLayer.Services return result; } + + public async Task<ServiceResult<List<UserGradeDto>>> GetUserGrades(int courseId) + { + var result = new ServiceResult<List<UserGradeDto>>(); + + var course = await _context.Courses + .Include(x => x.StudentCourses) + .ThenInclude(x => x.Student) + .FirstOrDefaultAsync(x => x.Id == courseId); + + if (!course.StudentCourses.Any()) + { + result.HasError = true; + result.AddMessage(string.Format(ErrorMessages.CourseHasNoStudents, courseId)); + return result; + } + + // TODO: obtain the grade from StudentCourses + result.Data = course.StudentCourses.Select(x => new UserGradeDto() + { + Grade = 10, + IdentityCard = x.Student.IdentityCard + }).ToList(); + + return result; + } } } diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Tsi1.BusinessLayer.csproj b/Tsi1.Api/Tsi1.BusinessLayer/Tsi1.BusinessLayer.csproj index a18735ed0c8c52887e85611f1b353106330f869f..d2c88dff5dce9ee2149d7e3b785110d593d0894d 100644 --- a/Tsi1.Api/Tsi1.BusinessLayer/Tsi1.BusinessLayer.csproj +++ b/Tsi1.Api/Tsi1.BusinessLayer/Tsi1.BusinessLayer.csproj @@ -11,6 +11,7 @@ <PackageReference Include="Microsoft.AspNetCore.Hosting.Abstractions" Version="2.2.0" /> <PackageReference Include="Microsoft.AspNetCore.Http.Features" Version="3.1.9" /> <PackageReference Include="MimeKit" Version="2.9.2" /> + <PackageReference Include="Newtonsoft.Json" Version="12.0.3" /> </ItemGroup> <ItemGroup>