diff --git a/Tsi1.Api/Tsi1.Api/Controllers/StudentCourseResultController.cs b/Tsi1.Api/Tsi1.Api/Controllers/StudentCourseResultController.cs new file mode 100644 index 0000000000000000000000000000000000000000..7767d5b87727735ca8caa605ab26fd7bcb55fb6b --- /dev/null +++ b/Tsi1.Api/Tsi1.Api/Controllers/StudentCourseResultController.cs @@ -0,0 +1,105 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Tsi1.BusinessLayer.Dtos; +using Tsi1.BusinessLayer.Helpers; +using Tsi1.BusinessLayer.Interfaces; + +namespace Tsi1.Api.Controllers +{ + [Route("api/[controller]")] + [ApiController] + public class StudentCourseResultController : ControllerBase + { + private readonly IStudentCourseResultService _studentCourseResultService; + + public StudentCourseResultController(IStudentCourseResultService studentCourseResultService) + { + _studentCourseResultService = studentCourseResultService; + } + + [Authorize(Roles = UserTypes.Student)] + [HttpGet("GetMyHistoricResults/{courseId}")] + public async Task<IActionResult> GetMyHistoricResults(int courseId) + { + var userId = int.Parse(HttpContext.User.Claims.FirstOrDefault(x => x.Type == "Id").Value); + + var result = await _studentCourseResultService.GetMyHistoricResults(courseId, userId); + + if (result.HasError) + { + return BadRequest(result.Message); + } + + return Ok(result.Data); + } + + [Authorize(Roles = UserTypes.Student)] + [HttpGet("GetMyLastResult/{courseId}")] + public async Task<IActionResult> GetMyLastResult(int courseId) + { + var userId = int.Parse(HttpContext.User.Claims.FirstOrDefault(x => x.Type == "Id").Value); + + var result = await _studentCourseResultService.GetMyLastResult(courseId, userId); + + if (result.HasError) + { + return BadRequest(result.Message); + } + + return Ok(result.Data); + } + + [Authorize(Roles = UserTypes.Professor)] + [HttpGet("GetLastStudentCourseResults/{courseId}")] + public async Task<IActionResult> GetLastStudentCourseResults(int courseId) + { + var userId = int.Parse(HttpContext.User.Claims.FirstOrDefault(x => x.Type == "Id").Value); + + var result = await _studentCourseResultService.GetLastStudentCourseResults(courseId, userId); + + if (result.HasError) + { + return BadRequest(result.Message); + } + + return Ok(result.Data); + } + + [Authorize(Roles = UserTypes.FacultyAdmin + ", " + UserTypes.Professor)] + [HttpPost("Create")] + public async Task<IActionResult> Create(StudentCourseResultCreateDto studentCourseResultDto) + { + var userId = int.Parse(HttpContext.User.Claims.FirstOrDefault(x => x.Type == "Id").Value); + + var result = await _studentCourseResultService.Create(studentCourseResultDto, userId); + + if (result.HasError) + { + return BadRequest(result.Message); + } + + return Ok(result.Data); + } + + [Authorize(Roles = UserTypes.Professor)] + [HttpDelete("Delete/{studentCourseResultId}")] + public async Task<IActionResult> Delete(int studentCourseResultId) + { + var userId = int.Parse(HttpContext.User.Claims.FirstOrDefault(x => x.Type == "Id").Value); + + var result = await _studentCourseResultService.Delete(studentCourseResultId, userId); + + 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 9371b171baa4553f36c92be15128a8dfa05fc868..31c8cf872d07f6e17ffa5de7bcb2cb3cbec10204 100644 --- a/Tsi1.Api/Tsi1.Api/Startup.cs +++ b/Tsi1.Api/Tsi1.Api/Startup.cs @@ -108,6 +108,7 @@ namespace Tsi1.Api services.AddScoped<IActivityService, ActivityService>(); services.AddScoped<IEvaluationService, EvaluationService>(); services.AddScoped<IEvaluationTypeService, EvaluationTypeService>(); + services.AddScoped<IStudentCourseResultService, StudentCourseResultService>(); services.AddSingleton<PresenceTracker>(); diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Dtos/StudentCourseResultCreateDto.cs b/Tsi1.Api/Tsi1.BusinessLayer/Dtos/StudentCourseResultCreateDto.cs new file mode 100644 index 0000000000000000000000000000000000000000..64cb01dde3e7381a3dd069624682ab2f9977c22d --- /dev/null +++ b/Tsi1.Api/Tsi1.BusinessLayer/Dtos/StudentCourseResultCreateDto.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Tsi1.BusinessLayer.Dtos +{ + public class StudentCourseResultCreateDto + { + public int Result { get; set; } + public int StudentId { get; set; } + public int CourseId { get; set; } + } +} diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Dtos/StudentCourseResultPreviewDto.cs b/Tsi1.Api/Tsi1.BusinessLayer/Dtos/StudentCourseResultPreviewDto.cs new file mode 100644 index 0000000000000000000000000000000000000000..b1ca70a88385bfce974b5b4d9873940eda483caf --- /dev/null +++ b/Tsi1.Api/Tsi1.BusinessLayer/Dtos/StudentCourseResultPreviewDto.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Tsi1.BusinessLayer.Dtos +{ + public class StudentCourseResultPreviewDto + { + public int Id { get; set; } + + public int Result { get; set; } + + public DateTime Date { get; set; } + + public int StudentId { get; set; } + public int CourseId { get; set; } + } +} diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Helpers/CourseApproval.cs b/Tsi1.Api/Tsi1.BusinessLayer/Helpers/CourseApproval.cs new file mode 100644 index 0000000000000000000000000000000000000000..bc2af854e47deed3606e27b8b598598d78df2433 --- /dev/null +++ b/Tsi1.Api/Tsi1.BusinessLayer/Helpers/CourseApproval.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Tsi1.BusinessLayer.Helpers +{ + public static class CourseApproval + { + public const int MinimumApproval = 3; + } +} diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Helpers/ErrorMessages.cs b/Tsi1.Api/Tsi1.BusinessLayer/Helpers/ErrorMessages.cs index 729cb7d42c1606ac9d6ff24eebb67f9d759c904c..34821215ec64c70529734527a8366ea7877c19e5 100644 --- a/Tsi1.Api/Tsi1.BusinessLayer/Helpers/ErrorMessages.cs +++ b/Tsi1.Api/Tsi1.BusinessLayer/Helpers/ErrorMessages.cs @@ -84,5 +84,8 @@ namespace Tsi1.BusinessLayer.Helpers public const string VideoConferenceIsNotEvaluation = "Una video conferencia no es una evaluación"; + public const string CourseAlreadyApproved = "El estudiante '{0}' ya aprovó el curso '{1}'"; + + public const string StudentCourseResultDoesNotExist = "El resultado con id '{0}' no existe"; } } diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Helpers/MappingProfile.cs b/Tsi1.Api/Tsi1.BusinessLayer/Helpers/MappingProfile.cs index 3aa435066b2e000daffb77b922b2fb9584d7af0f..a6029a5ad5a633e415472c6e64a695f5d450c409 100644 --- a/Tsi1.Api/Tsi1.BusinessLayer/Helpers/MappingProfile.cs +++ b/Tsi1.Api/Tsi1.BusinessLayer/Helpers/MappingProfile.cs @@ -67,6 +67,8 @@ namespace Tsi1.BusinessLayer.Helpers CreateMap<Evaluation, EvaluationModifyDto>(); CreateMap<Evaluation, EvaluationDetailDto>(); CreateMap<EvaluationInscription, EvaluationInscriptionDto>(); + CreateMap<StudentCourseResult, StudentCourseResultCreateDto>(); + CreateMap<StudentCourseResult, StudentCourseResultPreviewDto>(); CreateMap<Course, CourseModifyDto>(); CreateMap<ForumCreateDto, Forum>(); @@ -121,6 +123,8 @@ namespace Tsi1.BusinessLayer.Helpers CreateMap<EvaluationModifyDto, Evaluation>().ForMember(x => x.Id, opt => opt.Ignore()); CreateMap<EvaluationDetailDto, Evaluation>(); CreateMap<EvaluationInscriptionDto, EvaluationInscription>(); + CreateMap<StudentCourseResultCreateDto, StudentCourseResult>(); + CreateMap<StudentCourseResultPreviewDto, StudentCourseResult>(); CreateMap<CourseModifyDto, Course>(); } } diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Interfaces/IStudentCourseResultService.cs b/Tsi1.Api/Tsi1.BusinessLayer/Interfaces/IStudentCourseResultService.cs new file mode 100644 index 0000000000000000000000000000000000000000..5fdec183e893622ae5a4ca376d12e8ef2bb828ba --- /dev/null +++ b/Tsi1.Api/Tsi1.BusinessLayer/Interfaces/IStudentCourseResultService.cs @@ -0,0 +1,22 @@ +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 IStudentCourseResultService + { + Task<ServiceResult<int>> Create(StudentCourseResultCreateDto studentCourseResultDto, int userId); + + Task<ServiceResult<int>> Delete(int studentCourseResultId, int userId); + + Task<ServiceResult<List<StudentCourseResultPreviewDto>>> GetMyHistoricResults(int courseId, int userId); + + Task<ServiceResult<StudentCourseResultPreviewDto>> GetMyLastResult(int courseId, int userId); + + Task<ServiceResult<List<StudentCourseResultPreviewDto>>> GetLastStudentCourseResults(int courseId, int userId); + } +} diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Services/ActivityService.cs b/Tsi1.Api/Tsi1.BusinessLayer/Services/ActivityService.cs index ff629d1eaee7cfffdfc00419d14273957ef18405..67c239ff615099c447889b0e9ff8b1b6cb0e3328 100644 --- a/Tsi1.Api/Tsi1.BusinessLayer/Services/ActivityService.cs +++ b/Tsi1.Api/Tsi1.BusinessLayer/Services/ActivityService.cs @@ -151,7 +151,11 @@ namespace Tsi1.BusinessLayer.Services return result; } - var activities = await _context.Activities.AsNoTracking().Where(x => x.CourseId == courseId).ToListAsync(); + var activities = await _context.Activities + .AsNoTracking() + .Where(x => x.CourseId == courseId) + .OrderBy(x => x.Date) + .ToListAsync(); result.Data = _mapper.Map<List<ActivityDto>>(activities); return result; diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Services/StudentCourseResultService.cs b/Tsi1.Api/Tsi1.BusinessLayer/Services/StudentCourseResultService.cs new file mode 100644 index 0000000000000000000000000000000000000000..1f2a16dca15d27e8ec3a6761c5896f3f3e7a2937 --- /dev/null +++ b/Tsi1.Api/Tsi1.BusinessLayer/Services/StudentCourseResultService.cs @@ -0,0 +1,307 @@ +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 StudentCourseResultService : IStudentCourseResultService + { + private readonly Tsi1Context _context; + private readonly IMapper _mapper; + + public StudentCourseResultService(Tsi1Context context, IMapper mapper) + { + _context = context; + _mapper = mapper; + } + + public async Task<ServiceResult<int>> Create(StudentCourseResultCreateDto studentCourseResultDto, int userId) + { + var result = new ServiceResult<int>(); + + var studentValidation = await this.StudentCourseResultValidations(studentCourseResultDto.CourseId, studentCourseResultDto.StudentId); + + if (studentValidation.HasError) + { + result.HasError = true; + result.AddMessage(studentValidation.Message); + return result; + } + + var courseResult = await _context.StudentCourseResults + .AsNoTracking() + .FirstOrDefaultAsync(x => x.StudentId == studentCourseResultDto.StudentId + && x.CourseId == studentCourseResultDto.CourseId + && x.Result >= CourseApproval.MinimumApproval); + + if (courseResult != null) + { + result.HasError = true; + result.AddMessage(string.Format(ErrorMessages.CourseAlreadyApproved, studentCourseResultDto.StudentId, studentCourseResultDto.CourseId)); + return result; + } + + var professorValidation = await this.ProfessorValidations(studentCourseResultDto.CourseId, userId); + + if (professorValidation.HasError) + { + result.HasError = true; + result.AddMessage(professorValidation.Message); + return result; + } + + var studentCourseResult = _mapper.Map<StudentCourseResult>(studentCourseResultDto); + studentCourseResult.Date = DateTime.Now; + + _context.StudentCourseResults.Add(studentCourseResult); + + await _context.SaveChangesAsync(); + + result.Data = studentCourseResult.Id; + return result; + } + + public async Task<ServiceResult<int>> Delete(int studentCourseResultId, int userId) + { + var result = new ServiceResult<int>(); + + var studentCourseResult = await _context.StudentCourseResults.FirstOrDefaultAsync(x => x.Id == studentCourseResultId); + + if (studentCourseResult == null) + { + result.HasError = true; + result.AddMessage(string.Format(ErrorMessages.StudentCourseResultDoesNotExist, studentCourseResultId)); + return result; + } + + var professorValidation = await this.ProfessorValidations(studentCourseResult.CourseId, userId); + + if (professorValidation.HasError) + { + result.HasError = true; + result.AddMessage(professorValidation.Message); + return result; + } + + _context.StudentCourseResults.Remove(studentCourseResult); + + await _context.SaveChangesAsync(); + + return result; + } + + public async Task<ServiceResult<List<StudentCourseResultPreviewDto>>> GetLastStudentCourseResults(int courseId, int userId) + { + var result = new ServiceResult<List<StudentCourseResultPreviewDto>>(); + + var professorValidation = await this.ProfessorValidations(courseId, userId); + + if (professorValidation.HasError) + { + result.HasError = true; + result.AddMessage(professorValidation.Message); + return result; + } + + var studentIds = await _context.StudentCourses + .AsNoTracking() + .Where(x => x.CourseId == courseId) + .Select(x => x.StudentId) + .ToListAsync(); + + var auxStudentCourseResults = await _context.StudentCourseResults + .AsNoTracking() + .Where(x => x.CourseId == courseId && studentIds.Contains(x.StudentId)) + .ToListAsync(); + + var studentCourseResults = auxStudentCourseResults.GroupBy(x => new { x.StudentId, x.CourseId }) + .Select(x => x.OrderByDescending(g => g.Date).First()) + .ToList(); + + result.Data = _mapper.Map<List<StudentCourseResultPreviewDto>>(studentCourseResults); + + return result; + } + + public async Task<ServiceResult<List<StudentCourseResultPreviewDto>>> GetMyHistoricResults(int courseId, int userId) + { + var result = new ServiceResult<List<StudentCourseResultPreviewDto>>(); + + var userValidation = await this.UserValidation(userId); + + if (userValidation.HasError) + { + result.HasError = true; + result.AddMessage(userValidation.Message); + return result; + } + + var studentId = userValidation.Data; + + var studentValidation = await this.StudentCourseResultValidations(courseId, studentId); + + if (studentValidation.HasError) + { + result.HasError = true; + result.AddMessage(studentValidation.Message); + return result; + } + + var studentCourseResults = await _context.StudentCourseResults + .AsNoTracking() + .Where(x => x.CourseId == courseId && x.StudentId == studentId) + .OrderByDescending(x => x.Date) + .ToListAsync(); + + result.Data = _mapper.Map<List<StudentCourseResultPreviewDto>>(studentCourseResults); + + return result; + } + + public async Task<ServiceResult<StudentCourseResultPreviewDto>> GetMyLastResult(int courseId, int userId) + { + var result = new ServiceResult<StudentCourseResultPreviewDto>(); + + var userValidation = await this.UserValidation(userId); + + if (userValidation.HasError) + { + result.HasError = true; + result.AddMessage(userValidation.Message); + return result; + } + + var studentId = userValidation.Data; + + var studentValidation = await this.StudentCourseResultValidations(courseId, studentId); + + if (studentValidation.HasError) + { + result.HasError = true; + result.AddMessage(studentValidation.Message); + return result; + } + + var studentCourseResult = await _context.StudentCourseResults + .AsNoTracking() + .Where(x => x.CourseId == courseId && x.StudentId == studentId) + .OrderByDescending(x => x.Date) + .FirstOrDefaultAsync(); + + result.Data = _mapper.Map<StudentCourseResultPreviewDto>(studentCourseResult); + + return result; + } + + private async Task<ServiceResult<int>> StudentCourseResultValidations(int courseId, int studentId) + { + var result = new ServiceResult<int>(); + + var student = await _context.Students + .AsNoTracking() + .FirstOrDefaultAsync(x => x.Id == studentId); + + if (student == null) + { + result.HasError = true; + result.AddMessage(string.Format(ErrorMessages.StudentDoesNotExist, studentId)); + return result; + } + + var course = await _context.Courses + .AsNoTracking() + .FirstOrDefaultAsync(x => x.Id == courseId); + + if (course == null) + { + result.HasError = true; + result.AddMessage(string.Format(ErrorMessages.CourseDoesNotExist, courseId)); + return result; + } + + var studentCourse = await _context.StudentCourses + .AsNoTracking() + .FirstOrDefaultAsync(x => x.CourseId == courseId && x.StudentId == studentId); + + if (studentCourse == null) + { + result.HasError = true; + result.AddMessage(string.Format(ErrorMessages.StudentCourseDoesNotExists, studentId, courseId)); + return result; + } + + return result; + } + + private async Task<ServiceResult<int>> ProfessorValidations(int courseId, int userId) + { + var result = new ServiceResult<int>(); + + var user = await _context.Users + .AsNoTracking() + .Include(x => x.Professor) + .FirstOrDefaultAsync(x => x.Id == userId); + + if (user == null || user.Professor == null) + { + result.HasError = true; + result.AddMessage(string.Format(ErrorMessages.UserDoesNotExist, userId)); + return result; + } + + var course = await _context.Courses + .AsNoTracking() + .FirstOrDefaultAsync(x => x.Id == courseId); + + if (course == null) + { + result.HasError = true; + result.AddMessage(string.Format(ErrorMessages.CourseDoesNotExist, course)); + return result; + } + + var professorCourse = await _context.ProfessorCourses + .AsNoTracking() + .FirstOrDefaultAsync(x => x.CourseId == courseId && x.ProfessorId == user.ProfessorId); + + if (professorCourse == null) + { + result.HasError = true; + result.AddMessage(string.Format(ErrorMessages.ProfessorCourseDoesNotExists, user.ProfessorId, courseId)); + return result; + } + + + + return result; + } + + private async Task<ServiceResult<int>> UserValidation(int userId) + { + var result = new ServiceResult<int>(); + + var user = await _context.Users + .AsNoTracking() + .FirstOrDefaultAsync(x => x.Id == userId); + + if (user == null) + { + result.HasError = true; + result.AddMessage(string.Format(ErrorMessages.UserDoesNotExist, userId)); + return result; + } + + result.Data = (int)user.StudentId; + return result; + } + } +} diff --git a/Tsi1.Api/Tsi1.DataLayer/Entities/Course.cs b/Tsi1.Api/Tsi1.DataLayer/Entities/Course.cs index 5775fe7ca51db02cb80c84a819a7fcc55170620d..e47403864492be2d358b8da68e49ad78d5f840df 100644 --- a/Tsi1.Api/Tsi1.DataLayer/Entities/Course.cs +++ b/Tsi1.Api/Tsi1.DataLayer/Entities/Course.cs @@ -13,6 +13,7 @@ namespace Tsi1.DataLayer.Entities Sections = new HashSet<Section>(); Communications = new HashSet<Communication>(); Activities = new HashSet<Activity>(); + StudentCourseResults = new HashSet<StudentCourseResult>(); } public int Id { get; set; } @@ -30,5 +31,7 @@ namespace Tsi1.DataLayer.Entities public ICollection<Communication> Communications { get; set; } public ICollection<Activity> Activities { get; set; } + + public ICollection<StudentCourseResult> StudentCourseResults { get; set; } } } diff --git a/Tsi1.Api/Tsi1.DataLayer/Entities/Student.cs b/Tsi1.Api/Tsi1.DataLayer/Entities/Student.cs index cccbc18bb41494afc8179a2528185e114bd8707f..e6c50ad43e7753ca7d1cb316340e03696d4de4b5 100644 --- a/Tsi1.Api/Tsi1.DataLayer/Entities/Student.cs +++ b/Tsi1.Api/Tsi1.DataLayer/Entities/Student.cs @@ -11,6 +11,7 @@ namespace Tsi1.DataLayer.Entities StudentCourses = new HashSet<StudentCourse>(); EvaluationInscriptions = new HashSet<EvaluationInscription>(); Submissions = new HashSet<Submission>(); + StudentCourseResults = new HashSet<StudentCourseResult>(); } public int Id { get; set; } @@ -26,5 +27,7 @@ namespace Tsi1.DataLayer.Entities public ICollection<EvaluationInscription> EvaluationInscriptions { get; set; } public ICollection<Submission> Submissions { get; set; } + + public ICollection<StudentCourseResult> StudentCourseResults { get; set; } } } diff --git a/Tsi1.Api/Tsi1.DataLayer/Entities/StudentCourseResult.cs b/Tsi1.Api/Tsi1.DataLayer/Entities/StudentCourseResult.cs new file mode 100644 index 0000000000000000000000000000000000000000..443110aa1aaad0fd15d0310bcd0ed472553c7dcf --- /dev/null +++ b/Tsi1.Api/Tsi1.DataLayer/Entities/StudentCourseResult.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Tsi1.DataLayer.Entities +{ + public class StudentCourseResult + { + public int Id { get; set; } + + public int Result { get; set; } + + public DateTime Date { get; set; } + + public int StudentId { get; set; } + public int CourseId { get; set; } + + public Student Student { get; set; } + public Course Course { get; set; } + } +} diff --git a/Tsi1.Api/Tsi1.DataLayer/EntityConfiguration/StudentCourseResultConfiguration.cs b/Tsi1.Api/Tsi1.DataLayer/EntityConfiguration/StudentCourseResultConfiguration.cs new file mode 100644 index 0000000000000000000000000000000000000000..6149b85d8322b2b8b69522ee25549c25b341a3c7 --- /dev/null +++ b/Tsi1.Api/Tsi1.DataLayer/EntityConfiguration/StudentCourseResultConfiguration.cs @@ -0,0 +1,32 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; +using System; +using System.Collections.Generic; +using System.Text; +using Tsi1.DataLayer.Entities; + +namespace Tsi1.DataLayer.EntityConfiguration +{ + public class StudentCourseResultConfiguration : IEntityTypeConfiguration<StudentCourseResult> + { + public void Configure(EntityTypeBuilder<StudentCourseResult> builder) + { + builder.HasKey(x => x.Id); + + builder.Property(x => x.Result) + .IsRequired() + .HasColumnType("integer"); + + builder.Property(x => x.Date) + .IsRequired(); + + builder.HasOne(x => x.Course) + .WithMany(x => x.StudentCourseResults) + .HasForeignKey(x => x.CourseId); + + builder.HasOne(x => x.Student) + .WithMany(x => x.StudentCourseResults) + .HasForeignKey(x => x.StudentId); + } + } +} diff --git a/Tsi1.Api/Tsi1.DataLayer/Migrations/20201210234850_add-entity-StudentCourseResult.Designer.cs b/Tsi1.Api/Tsi1.DataLayer/Migrations/20201210234850_add-entity-StudentCourseResult.Designer.cs new file mode 100644 index 0000000000000000000000000000000000000000..57e7916417d90845729e1231e0e381a4fd9aeae2 --- /dev/null +++ b/Tsi1.Api/Tsi1.DataLayer/Migrations/20201210234850_add-entity-StudentCourseResult.Designer.cs @@ -0,0 +1,1113 @@ +// <auto-generated /> +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; +using Tsi1.DataLayer; + +namespace Tsi1.DataLayer.Migrations +{ + [DbContext(typeof(Tsi1Context))] + [Migration("20201210234850_add-entity-StudentCourseResult")] + partial class addentityStudentCourseResult + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn) + .HasAnnotation("ProductVersion", "3.1.4") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + modelBuilder.Entity("Tsi1.DataLayer.Entities.Activity", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property<int>("CourseId") + .HasColumnType("integer"); + + b.Property<DateTime>("Date") + .HasColumnType("timestamp without time zone"); + + b.Property<int?>("EvaluationId") + .HasColumnType("integer"); + + b.Property<bool>("IsVideoConference") + .HasColumnType("boolean"); + + b.Property<string>("Name") + .IsRequired() + .HasColumnType("character varying(50)"); + + b.HasKey("Id"); + + b.HasIndex("CourseId"); + + b.HasIndex("EvaluationId") + .IsUnique(); + + b.ToTable("Activities"); + }); + + modelBuilder.Entity("Tsi1.DataLayer.Entities.AnswerOption", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property<string>("Name") + .IsRequired() + .HasColumnType("character varying(100)"); + + b.HasKey("Id"); + + b.HasIndex("Name"); + + b.ToTable("AnswerOptions"); + }); + + modelBuilder.Entity("Tsi1.DataLayer.Entities.Attendance", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property<int>("ActivityId") + .HasColumnType("integer"); + + b.Property<DateTime>("Date") + .HasColumnType("timestamp without time zone"); + + b.Property<int>("UserId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ActivityId"); + + b.HasIndex("UserId"); + + b.ToTable("Attendances"); + }); + + modelBuilder.Entity("Tsi1.DataLayer.Entities.Communication", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property<int?>("CourseId") + .HasColumnType("integer"); + + b.Property<bool>("IsGlobal") + .HasColumnType("boolean"); + + b.Property<int?>("TenantId") + .HasColumnType("integer"); + + b.Property<string>("Text") + .IsRequired() + .HasColumnType("character varying(1000)"); + + b.Property<DateTime>("ValidUntil") + .HasColumnType("timestamp without time zone"); + + b.HasKey("Id"); + + b.HasIndex("CourseId"); + + b.HasIndex("TenantId"); + + b.HasIndex("ValidUntil"); + + b.ToTable("Communications"); + }); + + modelBuilder.Entity("Tsi1.DataLayer.Entities.Connection", b => + { + b.Property<string>("ConnectionId") + .HasColumnType("text"); + + b.Property<string>("GroupName") + .HasColumnType("text"); + + b.Property<int>("UserId") + .HasColumnType("integer"); + + b.HasKey("ConnectionId"); + + b.HasIndex("GroupName"); + + b.ToTable("Connections"); + }); + + modelBuilder.Entity("Tsi1.DataLayer.Entities.Course", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property<bool>("IsTemplate") + .HasColumnType("boolean"); + + b.Property<string>("Name") + .IsRequired() + .HasColumnType("character varying(50)"); + + b.Property<int>("TenantId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.HasIndex("Name", "TenantId") + .IsUnique(); + + b.ToTable("Courses"); + }); + + modelBuilder.Entity("Tsi1.DataLayer.Entities.Evaluation", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property<int>("EvaluationTypeId") + .HasColumnType("integer"); + + b.Property<bool>("IsCompleted") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.HasIndex("EvaluationTypeId"); + + b.ToTable("Evaluations"); + }); + + modelBuilder.Entity("Tsi1.DataLayer.Entities.EvaluationInscription", b => + { + b.Property<int>("EvaluationId") + .HasColumnType("integer"); + + b.Property<int>("StudentId") + .HasColumnType("integer"); + + b.Property<decimal>("Grade") + .HasColumnType("decimal(5,2)"); + + b.Property<bool>("HasAttended") + .HasColumnType("boolean"); + + b.HasKey("EvaluationId", "StudentId"); + + b.HasIndex("StudentId"); + + b.ToTable("EvaluationInscriptions"); + }); + + modelBuilder.Entity("Tsi1.DataLayer.Entities.EvaluationType", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property<string>("Name") + .IsRequired() + .HasColumnType("character varying(50)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("EvaluationTypes"); + }); + + modelBuilder.Entity("Tsi1.DataLayer.Entities.File", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property<bool>("IsSubmission") + .HasColumnType("boolean"); + + b.Property<string>("Name") + .IsRequired() + .HasColumnType("character varying(50)"); + + b.Property<string>("Path") + .IsRequired() + .HasColumnType("character varying(1000)"); + + b.Property<int?>("SubmissionId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("Path") + .IsUnique(); + + b.HasIndex("SubmissionId") + .IsUnique(); + + b.ToTable("Files"); + }); + + modelBuilder.Entity("Tsi1.DataLayer.Entities.Forum", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property<bool>("IsAutomaticSubscription") + .HasColumnType("boolean"); + + b.Property<string>("Name") + .IsRequired() + .HasColumnType("character varying(50)"); + + b.HasKey("Id"); + + b.ToTable("Forums"); + }); + + modelBuilder.Entity("Tsi1.DataLayer.Entities.ForumUser", b => + { + b.Property<int>("ForumId") + .HasColumnType("integer"); + + b.Property<int>("UserId") + .HasColumnType("integer"); + + b.HasKey("ForumId", "UserId"); + + b.HasIndex("UserId"); + + b.ToTable("ForumUsers"); + }); + + modelBuilder.Entity("Tsi1.DataLayer.Entities.Group", b => + { + b.Property<string>("Name") + .HasColumnType("text"); + + b.HasKey("Name"); + + b.ToTable("Groups"); + }); + + modelBuilder.Entity("Tsi1.DataLayer.Entities.Post", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property<DateTime>("Date") + .HasColumnType("timestamp without time zone"); + + b.Property<int>("ForumId") + .HasColumnType("integer"); + + b.Property<string>("Title") + .IsRequired() + .HasColumnType("character varying(100)"); + + b.Property<int>("UserId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.HasIndex("ForumId", "Title") + .IsUnique(); + + b.ToTable("Posts"); + }); + + modelBuilder.Entity("Tsi1.DataLayer.Entities.PostMessage", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property<string>("Content") + .IsRequired() + .HasColumnType("character varying(10485760)"); + + b.Property<DateTime>("Date") + .HasColumnType("timestamp without time zone"); + + b.Property<int>("PostId") + .HasColumnType("integer"); + + b.Property<int>("UserId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("PostId"); + + b.HasIndex("UserId"); + + b.ToTable("PostMessages"); + }); + + modelBuilder.Entity("Tsi1.DataLayer.Entities.Professor", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property<string>("IdentityCard") + .IsRequired() + .HasColumnType("character varying(50)"); + + b.Property<int>("TenantId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.HasIndex("IdentityCard", "TenantId") + .IsUnique(); + + b.ToTable("Professors"); + }); + + modelBuilder.Entity("Tsi1.DataLayer.Entities.ProfessorCourse", b => + { + b.Property<int>("ProfessorId") + .HasColumnType("integer"); + + b.Property<int>("CourseId") + .HasColumnType("integer"); + + b.HasKey("ProfessorId", "CourseId"); + + b.HasIndex("CourseId"); + + b.ToTable("ProfessorCourses"); + }); + + modelBuilder.Entity("Tsi1.DataLayer.Entities.Section", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property<int>("CourseId") + .HasColumnType("integer"); + + b.Property<string>("Name") + .IsRequired() + .HasColumnType("character varying(255)"); + + b.Property<int>("Order") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("CourseId"); + + b.ToTable("Sections"); + }); + + modelBuilder.Entity("Tsi1.DataLayer.Entities.SectionItem", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property<int?>("FileId") + .HasColumnType("integer"); + + b.Property<int?>("ForumId") + .HasColumnType("integer"); + + b.Property<int>("Order") + .HasColumnType("integer"); + + b.Property<int>("SectionId") + .HasColumnType("integer"); + + b.Property<int>("SectionItemTypeId") + .HasColumnType("integer"); + + b.Property<int?>("SurveyId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("FileId") + .IsUnique(); + + b.HasIndex("ForumId") + .IsUnique(); + + b.HasIndex("SectionId"); + + b.HasIndex("SectionItemTypeId"); + + b.HasIndex("SurveyId") + .IsUnique(); + + b.ToTable("SectionItems"); + }); + + modelBuilder.Entity("Tsi1.DataLayer.Entities.SectionItemType", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property<string>("Name") + .IsRequired() + .HasColumnType("character varying(100)"); + + b.HasKey("Id"); + + b.ToTable("SectionItemTypes"); + }); + + modelBuilder.Entity("Tsi1.DataLayer.Entities.Student", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property<string>("IdentityCard") + .IsRequired() + .HasColumnType("character varying(50)"); + + b.Property<int>("TenantId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.HasIndex("IdentityCard", "TenantId") + .IsUnique(); + + b.ToTable("Students"); + }); + + modelBuilder.Entity("Tsi1.DataLayer.Entities.StudentCourse", b => + { + b.Property<int>("StudentId") + .HasColumnType("integer"); + + b.Property<int>("CourseId") + .HasColumnType("integer"); + + b.HasKey("StudentId", "CourseId"); + + b.HasIndex("CourseId"); + + b.ToTable("StudentCourses"); + }); + + modelBuilder.Entity("Tsi1.DataLayer.Entities.StudentCourseResult", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property<int>("CourseId") + .HasColumnType("integer"); + + b.Property<DateTime>("Date") + .HasColumnType("timestamp without time zone"); + + b.Property<int>("Result") + .HasColumnType("integer"); + + b.Property<int>("StudentId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("CourseId"); + + b.HasIndex("StudentId"); + + b.ToTable("StudentCourseResults"); + }); + + modelBuilder.Entity("Tsi1.DataLayer.Entities.Submission", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property<int?>("EvaluationId") + .HasColumnType("integer"); + + b.Property<int>("FileId") + .HasColumnType("integer"); + + b.Property<decimal>("Grade") + .HasColumnType("decimal(5,2)"); + + b.Property<bool>("IsCompleted") + .HasColumnType("boolean"); + + b.Property<int>("StudentId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("EvaluationId"); + + b.HasIndex("StudentId", "FileId") + .IsUnique(); + + b.ToTable("Submissions"); + }); + + modelBuilder.Entity("Tsi1.DataLayer.Entities.Survey", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property<bool>("IsGlobal") + .HasColumnType("boolean"); + + b.Property<string>("Name") + .IsRequired() + .HasColumnType("character varying(255)"); + + b.Property<int?>("TenantId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("Name"); + + b.HasIndex("TenantId"); + + b.ToTable("Surveys"); + }); + + modelBuilder.Entity("Tsi1.DataLayer.Entities.SurveyAnswer", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property<int>("AnswerOptionId") + .HasColumnType("integer"); + + b.Property<int>("SurveyQuestionId") + .HasColumnType("integer"); + + b.Property<int>("SurveyResponseId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("AnswerOptionId"); + + b.HasIndex("SurveyQuestionId"); + + b.HasIndex("SurveyResponseId"); + + b.ToTable("SurveyAnswers"); + }); + + modelBuilder.Entity("Tsi1.DataLayer.Entities.SurveyQuestion", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property<string>("Question") + .IsRequired() + .HasColumnType("character varying(255)"); + + b.Property<int>("SurveyId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("SurveyId"); + + b.ToTable("SurveyQuestions"); + }); + + modelBuilder.Entity("Tsi1.DataLayer.Entities.SurveyResponse", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property<int>("SurveyId") + .HasColumnType("integer"); + + b.Property<int>("UserId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("SurveyId"); + + b.HasIndex("UserId"); + + b.ToTable("SurveyResponses"); + }); + + modelBuilder.Entity("Tsi1.DataLayer.Entities.Tenant", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property<string>("Name") + .IsRequired() + .HasColumnType("character varying(50)"); + + b.Property<string>("Theme") + .IsRequired() + .HasColumnType("character varying(200)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Tenants"); + }); + + modelBuilder.Entity("Tsi1.DataLayer.Entities.User", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property<DateTime>("Birthdate") + .HasColumnType("timestamp without time zone"); + + b.Property<string>("Email") + .IsRequired() + .HasColumnType("character varying(255)"); + + b.Property<string>("FirstName") + .IsRequired() + .HasColumnType("character varying(255)"); + + b.Property<string>("LastName") + .IsRequired() + .HasColumnType("character varying(255)"); + + b.Property<string>("Password") + .IsRequired() + .HasColumnType("character varying(255)"); + + b.Property<int?>("ProfessorId") + .HasColumnType("integer"); + + b.Property<int?>("StudentId") + .HasColumnType("integer"); + + b.Property<int>("TenantId") + .HasColumnType("integer"); + + b.Property<int>("UserTypeId") + .HasColumnType("integer"); + + b.Property<string>("Username") + .IsRequired() + .HasColumnType("character varying(50)"); + + b.HasKey("Id"); + + b.HasIndex("ProfessorId") + .IsUnique(); + + b.HasIndex("StudentId") + .IsUnique(); + + b.HasIndex("TenantId"); + + b.HasIndex("UserTypeId"); + + b.HasIndex("Username", "TenantId") + .IsUnique(); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("Tsi1.DataLayer.Entities.UserType", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property<string>("Name") + .IsRequired() + .HasColumnType("character varying(50)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("UserTypes"); + }); + + modelBuilder.Entity("Tsi1.DataLayer.Entities.Activity", b => + { + b.HasOne("Tsi1.DataLayer.Entities.Course", "Course") + .WithMany("Activities") + .HasForeignKey("CourseId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Tsi1.DataLayer.Entities.Evaluation", "Evaluation") + .WithOne("Activity") + .HasForeignKey("Tsi1.DataLayer.Entities.Activity", "EvaluationId"); + }); + + modelBuilder.Entity("Tsi1.DataLayer.Entities.Attendance", b => + { + b.HasOne("Tsi1.DataLayer.Entities.Activity", "Activity") + .WithMany("Attendances") + .HasForeignKey("ActivityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Tsi1.DataLayer.Entities.User", "User") + .WithMany("Attendances") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Tsi1.DataLayer.Entities.Communication", b => + { + b.HasOne("Tsi1.DataLayer.Entities.Course", "Course") + .WithMany("Communications") + .HasForeignKey("CourseId"); + + b.HasOne("Tsi1.DataLayer.Entities.Tenant", "Tenant") + .WithMany("Communications") + .HasForeignKey("TenantId"); + }); + + modelBuilder.Entity("Tsi1.DataLayer.Entities.Connection", b => + { + b.HasOne("Tsi1.DataLayer.Entities.Group", "Group") + .WithMany("Connections") + .HasForeignKey("GroupName"); + }); + + modelBuilder.Entity("Tsi1.DataLayer.Entities.Course", b => + { + b.HasOne("Tsi1.DataLayer.Entities.Tenant", "Tenant") + .WithMany("Courses") + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Tsi1.DataLayer.Entities.Evaluation", b => + { + b.HasOne("Tsi1.DataLayer.Entities.EvaluationType", "EvaluationType") + .WithMany() + .HasForeignKey("EvaluationTypeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Tsi1.DataLayer.Entities.EvaluationInscription", b => + { + b.HasOne("Tsi1.DataLayer.Entities.Evaluation", "Evaluation") + .WithMany("EvaluationInscriptions") + .HasForeignKey("EvaluationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Tsi1.DataLayer.Entities.Student", "Student") + .WithMany("EvaluationInscriptions") + .HasForeignKey("StudentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Tsi1.DataLayer.Entities.File", b => + { + b.HasOne("Tsi1.DataLayer.Entities.Submission", "Submission") + .WithOne("File") + .HasForeignKey("Tsi1.DataLayer.Entities.File", "SubmissionId"); + }); + + modelBuilder.Entity("Tsi1.DataLayer.Entities.ForumUser", b => + { + b.HasOne("Tsi1.DataLayer.Entities.Forum", "Forum") + .WithMany("ForumUsers") + .HasForeignKey("ForumId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Tsi1.DataLayer.Entities.User", "User") + .WithMany("ForumUsers") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Tsi1.DataLayer.Entities.Post", b => + { + b.HasOne("Tsi1.DataLayer.Entities.Forum", "Forum") + .WithMany("Posts") + .HasForeignKey("ForumId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Tsi1.DataLayer.Entities.User", "User") + .WithMany("Posts") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Tsi1.DataLayer.Entities.PostMessage", b => + { + b.HasOne("Tsi1.DataLayer.Entities.Post", "Post") + .WithMany("PostMessages") + .HasForeignKey("PostId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Tsi1.DataLayer.Entities.User", "User") + .WithMany("PostMessages") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Tsi1.DataLayer.Entities.Professor", b => + { + b.HasOne("Tsi1.DataLayer.Entities.Tenant", "Tenant") + .WithMany("Professors") + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Tsi1.DataLayer.Entities.ProfessorCourse", b => + { + b.HasOne("Tsi1.DataLayer.Entities.Course", "Course") + .WithMany("ProfessorCourses") + .HasForeignKey("CourseId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Tsi1.DataLayer.Entities.Professor", "Professor") + .WithMany("ProfessorCourses") + .HasForeignKey("ProfessorId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Tsi1.DataLayer.Entities.Section", b => + { + b.HasOne("Tsi1.DataLayer.Entities.Course", "Course") + .WithMany("Sections") + .HasForeignKey("CourseId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Tsi1.DataLayer.Entities.SectionItem", b => + { + b.HasOne("Tsi1.DataLayer.Entities.File", "File") + .WithOne("SectionItem") + .HasForeignKey("Tsi1.DataLayer.Entities.SectionItem", "FileId"); + + b.HasOne("Tsi1.DataLayer.Entities.Forum", "Forum") + .WithOne("SectionItem") + .HasForeignKey("Tsi1.DataLayer.Entities.SectionItem", "ForumId"); + + b.HasOne("Tsi1.DataLayer.Entities.Section", "Section") + .WithMany("SectionItems") + .HasForeignKey("SectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Tsi1.DataLayer.Entities.SectionItemType", "SectionItemType") + .WithMany("SectionItems") + .HasForeignKey("SectionItemTypeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Tsi1.DataLayer.Entities.Survey", "Survey") + .WithOne("SectionItem") + .HasForeignKey("Tsi1.DataLayer.Entities.SectionItem", "SurveyId"); + }); + + modelBuilder.Entity("Tsi1.DataLayer.Entities.Student", b => + { + b.HasOne("Tsi1.DataLayer.Entities.Tenant", "Tenant") + .WithMany("Students") + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Tsi1.DataLayer.Entities.StudentCourse", b => + { + b.HasOne("Tsi1.DataLayer.Entities.Course", "Course") + .WithMany("StudentCourses") + .HasForeignKey("CourseId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Tsi1.DataLayer.Entities.Student", "Student") + .WithMany("StudentCourses") + .HasForeignKey("StudentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Tsi1.DataLayer.Entities.StudentCourseResult", b => + { + b.HasOne("Tsi1.DataLayer.Entities.Course", "Course") + .WithMany("StudentCourseResults") + .HasForeignKey("CourseId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Tsi1.DataLayer.Entities.Student", "Student") + .WithMany("StudentCourseResults") + .HasForeignKey("StudentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Tsi1.DataLayer.Entities.Submission", b => + { + b.HasOne("Tsi1.DataLayer.Entities.Evaluation", null) + .WithMany("Submissions") + .HasForeignKey("EvaluationId"); + + b.HasOne("Tsi1.DataLayer.Entities.Student", "Student") + .WithMany("Submissions") + .HasForeignKey("StudentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Tsi1.DataLayer.Entities.Survey", b => + { + b.HasOne("Tsi1.DataLayer.Entities.Tenant", "Tenant") + .WithMany("Surveys") + .HasForeignKey("TenantId"); + }); + + modelBuilder.Entity("Tsi1.DataLayer.Entities.SurveyAnswer", b => + { + b.HasOne("Tsi1.DataLayer.Entities.AnswerOption", "AnswerOption") + .WithMany("SurveyAnswers") + .HasForeignKey("AnswerOptionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Tsi1.DataLayer.Entities.SurveyQuestion", "SurveyQuestion") + .WithMany("SurveyAnswers") + .HasForeignKey("SurveyQuestionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Tsi1.DataLayer.Entities.SurveyResponse", "SurveyResponse") + .WithMany("SurveyAnswers") + .HasForeignKey("SurveyResponseId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Tsi1.DataLayer.Entities.SurveyQuestion", b => + { + b.HasOne("Tsi1.DataLayer.Entities.Survey", "Survey") + .WithMany("SurveyQuestions") + .HasForeignKey("SurveyId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Tsi1.DataLayer.Entities.SurveyResponse", b => + { + b.HasOne("Tsi1.DataLayer.Entities.Survey", "Survey") + .WithMany("SurveyResponses") + .HasForeignKey("SurveyId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Tsi1.DataLayer.Entities.User", "User") + .WithMany("SurveyResponses") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Tsi1.DataLayer.Entities.User", b => + { + b.HasOne("Tsi1.DataLayer.Entities.Professor", "Professor") + .WithOne("User") + .HasForeignKey("Tsi1.DataLayer.Entities.User", "ProfessorId"); + + b.HasOne("Tsi1.DataLayer.Entities.Student", "Student") + .WithOne("User") + .HasForeignKey("Tsi1.DataLayer.Entities.User", "StudentId"); + + b.HasOne("Tsi1.DataLayer.Entities.Tenant", "Tenant") + .WithMany("Users") + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Tsi1.DataLayer.Entities.UserType", "UserType") + .WithMany() + .HasForeignKey("UserTypeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Tsi1.Api/Tsi1.DataLayer/Migrations/20201210234850_add-entity-StudentCourseResult.cs b/Tsi1.Api/Tsi1.DataLayer/Migrations/20201210234850_add-entity-StudentCourseResult.cs new file mode 100644 index 0000000000000000000000000000000000000000..310e9e13e07c9a2e87bc9690bb82daf05af06b15 --- /dev/null +++ b/Tsi1.Api/Tsi1.DataLayer/Migrations/20201210234850_add-entity-StudentCourseResult.cs @@ -0,0 +1,56 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +namespace Tsi1.DataLayer.Migrations +{ + public partial class addentityStudentCourseResult : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "StudentCourseResults", + columns: table => new + { + Id = table.Column<int>(nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + Result = table.Column<int>(type: "integer", nullable: false), + Date = table.Column<DateTime>(nullable: false), + StudentId = table.Column<int>(nullable: false), + CourseId = table.Column<int>(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_StudentCourseResults", x => x.Id); + table.ForeignKey( + name: "FK_StudentCourseResults_Courses_CourseId", + column: x => x.CourseId, + principalTable: "Courses", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_StudentCourseResults_Students_StudentId", + column: x => x.StudentId, + principalTable: "Students", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_StudentCourseResults_CourseId", + table: "StudentCourseResults", + column: "CourseId"); + + migrationBuilder.CreateIndex( + name: "IX_StudentCourseResults_StudentId", + table: "StudentCourseResults", + column: "StudentId"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "StudentCourseResults"); + } + } +} diff --git a/Tsi1.Api/Tsi1.DataLayer/Migrations/Tsi1ContextModelSnapshot.cs b/Tsi1.Api/Tsi1.DataLayer/Migrations/Tsi1ContextModelSnapshot.cs index 9415937d1234a611f417e0cb81f2e4b2e359347b..841a7f13f37fe37a05d0ec4d53e853230c8e63e1 100644 --- a/Tsi1.Api/Tsi1.DataLayer/Migrations/Tsi1ContextModelSnapshot.cs +++ b/Tsi1.Api/Tsi1.DataLayer/Migrations/Tsi1ContextModelSnapshot.cs @@ -537,6 +537,34 @@ namespace Tsi1.DataLayer.Migrations b.ToTable("StudentCourses"); }); + modelBuilder.Entity("Tsi1.DataLayer.Entities.StudentCourseResult", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property<int>("CourseId") + .HasColumnType("integer"); + + b.Property<DateTime>("Date") + .HasColumnType("timestamp without time zone"); + + b.Property<int>("Result") + .HasColumnType("integer"); + + b.Property<int>("StudentId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("CourseId"); + + b.HasIndex("StudentId"); + + b.ToTable("StudentCourseResults"); + }); + modelBuilder.Entity("Tsi1.DataLayer.Entities.Submission", b => { b.Property<int>("Id") @@ -982,6 +1010,21 @@ namespace Tsi1.DataLayer.Migrations .IsRequired(); }); + modelBuilder.Entity("Tsi1.DataLayer.Entities.StudentCourseResult", b => + { + b.HasOne("Tsi1.DataLayer.Entities.Course", "Course") + .WithMany("StudentCourseResults") + .HasForeignKey("CourseId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Tsi1.DataLayer.Entities.Student", "Student") + .WithMany("StudentCourseResults") + .HasForeignKey("StudentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + modelBuilder.Entity("Tsi1.DataLayer.Entities.Submission", b => { b.HasOne("Tsi1.DataLayer.Entities.Evaluation", null) diff --git a/Tsi1.Api/Tsi1.DataLayer/Tsi1Context.cs b/Tsi1.Api/Tsi1.DataLayer/Tsi1Context.cs index cef2ed04e914bc9f2a34468270426eb90e72e347..50967e83b4f85eeeb398e2ec4a6df1bf48e55ddd 100644 --- a/Tsi1.Api/Tsi1.DataLayer/Tsi1Context.cs +++ b/Tsi1.Api/Tsi1.DataLayer/Tsi1Context.cs @@ -39,6 +39,7 @@ namespace Tsi1.DataLayer public DbSet<EvaluationInscription> EvaluationInscriptions { get; set; } public DbSet<Submission> Submissions { get; set; } public DbSet<EvaluationType> EvaluationTypes { get; set; } + public DbSet<StudentCourseResult> StudentCourseResults { get; set; } @@ -77,6 +78,7 @@ namespace Tsi1.DataLayer modelBuilder.ApplyConfiguration(new EvaluationInscriptionConfiguration()); modelBuilder.ApplyConfiguration(new SubmissionConfiguration()); modelBuilder.ApplyConfiguration(new EvaluationTypeConfiguration()); + modelBuilder.ApplyConfiguration(new StudentCourseResultConfiguration()); } } }