From c08610b9fd558e35534b2bb9f4d2395da3b15932 Mon Sep 17 00:00:00 2001 From: Lucca Santangelo <luccasant95@gmail.com> Date: Sat, 14 Nov 2020 17:17:36 -0300 Subject: [PATCH] course templates --- .../Tsi1.Api/Controllers/CourseController.cs | 31 +- .../Dtos/CourseCreateDto.cs | 1 + .../Dtos/CourseModifyDto.cs | 13 + .../Dtos/CourseTemplateCreateDto.cs | 12 + .../Helpers/ErrorMessages.cs | 3 +- .../Helpers/MappingProfile.cs | 7 + .../Interfaces/ICourseService.cs | 9 +- .../Services/CourseService.cs | 66 +- Tsi1.Api/Tsi1.DataLayer/Entities/Course.cs | 1 + .../CourseConfiguration.cs | 3 + ...20201112213633_course-template.Designer.cs | 611 ++++++++++++++++++ .../20201112213633_course-template.cs | 23 + .../Migrations/Tsi1ContextModelSnapshot.cs | 3 + 13 files changed, 762 insertions(+), 21 deletions(-) create mode 100644 Tsi1.Api/Tsi1.BusinessLayer/Dtos/CourseModifyDto.cs create mode 100644 Tsi1.Api/Tsi1.BusinessLayer/Dtos/CourseTemplateCreateDto.cs create mode 100644 Tsi1.Api/Tsi1.DataLayer/Migrations/20201112213633_course-template.Designer.cs create mode 100644 Tsi1.Api/Tsi1.DataLayer/Migrations/20201112213633_course-template.cs diff --git a/Tsi1.Api/Tsi1.Api/Controllers/CourseController.cs b/Tsi1.Api/Tsi1.Api/Controllers/CourseController.cs index 4a8d4b8..22545ba 100644 --- a/Tsi1.Api/Tsi1.Api/Controllers/CourseController.cs +++ b/Tsi1.Api/Tsi1.Api/Controllers/CourseController.cs @@ -170,10 +170,25 @@ namespace Tsi1.Api.Controllers return Ok(result.Data); } + [Authorize(Roles = UserTypes.FacultyAdmin)] + [HttpGet("GetAllTemplates")] + public async Task<IActionResult> GetAllTemplates() + { + var tenantId = int.Parse(HttpContext.User.Claims.FirstOrDefault(x => x.Type == "TenantId").Value); + + var result = await _courseService.GetAll(tenantId, true); + if (result.HasError) + { + return BadRequest(result.Message); + } + + return Ok(result.Data); + } + [Authorize(Roles = UserTypes.Professor + ", " + UserTypes.FacultyAdmin)] [HttpPut("Modify/{courseId}")] - public async Task<IActionResult> Modify(int courseId, CourseCreateDto courseDto) + public async Task<IActionResult> Modify(int courseId, CourseModifyDto courseDto) { var tenantId = int.Parse(HttpContext.User.Claims.FirstOrDefault(x => x.Type == "TenantId").Value); courseDto.TenantId = tenantId; @@ -238,5 +253,19 @@ namespace Tsi1.Api.Controllers return Ok(result.Data); } + [AllowAnonymous] + [Authorize(Roles = UserTypes.FacultyAdmin)] + [HttpPost("CreateFromTemplate")] + public async Task<IActionResult> CreateFromTemplate(CourseTemplateCreateDto courseTemplate) + { + var tenantId = int.Parse(HttpContext.User.Claims.FirstOrDefault(x => x.Type == "TenantId").Value); + + var result = await _courseService.CreateFromTemplate(courseTemplate, tenantId); + if (result.HasError) + { + return BadRequest(result.Message); + } + return Ok(); + } } } diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Dtos/CourseCreateDto.cs b/Tsi1.Api/Tsi1.BusinessLayer/Dtos/CourseCreateDto.cs index ffd3608..a3540f4 100644 --- a/Tsi1.Api/Tsi1.BusinessLayer/Dtos/CourseCreateDto.cs +++ b/Tsi1.Api/Tsi1.BusinessLayer/Dtos/CourseCreateDto.cs @@ -8,6 +8,7 @@ namespace Tsi1.BusinessLayer.Dtos public class CourseCreateDto { public string Name { get; set; } + public bool IsTemplate { get; set; } [JsonIgnore] public int TenantId { get; set; } diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Dtos/CourseModifyDto.cs b/Tsi1.Api/Tsi1.BusinessLayer/Dtos/CourseModifyDto.cs new file mode 100644 index 0000000..fe5599c --- /dev/null +++ b/Tsi1.Api/Tsi1.BusinessLayer/Dtos/CourseModifyDto.cs @@ -0,0 +1,13 @@ +using System.Text.Json.Serialization; + +namespace Tsi1.BusinessLayer.Dtos +{ + public class CourseModifyDto + { + public string Name { get; set; } + public bool IsTemplate { get; set; } + + [JsonIgnore] + public int TenantId { get; set; } + } +} diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Dtos/CourseTemplateCreateDto.cs b/Tsi1.Api/Tsi1.BusinessLayer/Dtos/CourseTemplateCreateDto.cs new file mode 100644 index 0000000..94924d7 --- /dev/null +++ b/Tsi1.Api/Tsi1.BusinessLayer/Dtos/CourseTemplateCreateDto.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Tsi1.BusinessLayer.Dtos +{ + public class CourseTemplateCreateDto + { + public string Name { get; set; } + public int CourseTemplateId { get; set; } + } +} diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Helpers/ErrorMessages.cs b/Tsi1.Api/Tsi1.BusinessLayer/Helpers/ErrorMessages.cs index 41b7cf0..a004f7a 100644 --- a/Tsi1.Api/Tsi1.BusinessLayer/Helpers/ErrorMessages.cs +++ b/Tsi1.Api/Tsi1.BusinessLayer/Helpers/ErrorMessages.cs @@ -31,8 +31,9 @@ namespace Tsi1.BusinessLayer.Helpers public const string CannotAuthenticateToSmtpServer = "No se pudo autenticar en el servidor SMTP"; public const string CannotSendEmail = "No se pudo mandar el mail con asunto {0}"; - public const string CourseDoesNotExist = "El curso '{0}' no existe"; + 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 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 4d7d53b..da9824d 100644 --- a/Tsi1.Api/Tsi1.BusinessLayer/Helpers/MappingProfile.cs +++ b/Tsi1.Api/Tsi1.BusinessLayer/Helpers/MappingProfile.cs @@ -72,6 +72,13 @@ namespace Tsi1.BusinessLayer.Helpers CreateMap<SectionDetailDto, Section>(); CreateMap<SectionItemDetailDto, SectionItem>(); CreateMap<FileDetailDto, File>(); + + CreateMap<Course, Course>().ForMember(x => x.Id, opt => opt.Ignore()); + CreateMap<Tenant, Tenant>().ForMember(x => x.Id, opt => opt.Ignore()); + CreateMap<Section, Section>().ForMember(x => x.Id, opt => opt.Ignore()); + CreateMap<SectionItem, SectionItem>().ForMember(x => x.Id, opt => opt.Ignore()); + CreateMap<SectionItemType, SectionItemType>().ForMember(x => x.Id, opt => opt.Ignore()); + CreateMap<Forum, Forum>().ForMember(x => x.Id, opt => opt.Ignore()); } } } diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Interfaces/ICourseService.cs b/Tsi1.Api/Tsi1.BusinessLayer/Interfaces/ICourseService.cs index 836612b..640e6ec 100644 --- a/Tsi1.Api/Tsi1.BusinessLayer/Interfaces/ICourseService.cs +++ b/Tsi1.Api/Tsi1.BusinessLayer/Interfaces/ICourseService.cs @@ -1,6 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Text; +using System.Collections.Generic; using System.Threading.Tasks; using Tsi1.BusinessLayer.Dtos; using Tsi1.BusinessLayer.Helpers; @@ -13,14 +11,15 @@ namespace Tsi1.BusinessLayer.Interfaces Task<ServiceResult<List<CoursePreviewDto>>> GetCoursePreviews(int userId, string userType); Task<ServiceResult<Course>> Create(CourseCreateDto newCourse); + Task<ServiceResult<bool>> CreateFromTemplate(CourseTemplateCreateDto courseTemplate, int tenantId); Task<ServiceResult<bool>> Matriculate(int userId, int courseId); Task<ServiceResult<bool>> AddProfessorToCourse(ProfessorCourseDto professorCourseDto); - Task<ServiceResult<List<CoursePreviewDto>>> GetAll(int tenantId); + Task<ServiceResult<List<CoursePreviewDto>>> GetAll(int tenantId, bool isTemplate = false); - Task<ServiceResult<bool>> Modify(int courseId, CourseCreateDto courseDto); + Task<ServiceResult<bool>> Modify(int courseId, CourseModifyDto courseDto); Task<ServiceResult<Course>> Delete(int courseId); diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Services/CourseService.cs b/Tsi1.Api/Tsi1.BusinessLayer/Services/CourseService.cs index fffcc93..8152ca0 100644 --- a/Tsi1.Api/Tsi1.BusinessLayer/Services/CourseService.cs +++ b/Tsi1.Api/Tsi1.BusinessLayer/Services/CourseService.cs @@ -97,6 +97,7 @@ namespace Tsi1.BusinessLayer.Services if (user == null || user.Student == null) { + result.HasError = true; result.Message = string.Format(ErrorMessages.UserDoesNotExist, userId); return result; } @@ -105,10 +106,18 @@ namespace Tsi1.BusinessLayer.Services if (course == null) { + result.HasError = true; result.Message = string.Format(ErrorMessages.CourseDoesNotExist, courseId); return result; } + if (course.IsTemplate) + { + result.HasError = true; + result.AddMessage(string.Format(ErrorMessages.CourseIsTemplate, courseId)); + return result; + } + var existingStudentCourse = await _context.StudentCourses .FirstOrDefaultAsync(x => x.StudentId == user.StudentId && x.CourseId == course.Id); @@ -144,6 +153,7 @@ namespace Tsi1.BusinessLayer.Services if (user == null || user.Professor == null) { + result.HasError = true; result.Message = string.Format(ErrorMessages.UserDoesNotExist, user.Username); return result; } @@ -153,10 +163,18 @@ namespace Tsi1.BusinessLayer.Services if (course == null) { + result.HasError = true; result.Message = string.Format(ErrorMessages.CourseDoesNotExist, professorCourseDto.CourseId); return result; } + if (course.IsTemplate) + { + result.HasError = true; + result.AddMessage(string.Format(ErrorMessages.CourseIsTemplate, professorCourseDto.CourseId)); + return result; + } + var existingProfessorCourse = await _context.ProfessorCourses .FirstOrDefaultAsync(x => x.ProfessorId == user.ProfessorId && x.CourseId == course.Id); @@ -174,30 +192,28 @@ namespace Tsi1.BusinessLayer.Services }; _context.ProfessorCourses.Add(professorCourse); - await _context.SaveChangesAsync(); result.Data = true; - return result; } - public async Task<ServiceResult<List<CoursePreviewDto>>> GetAll(int tenantId) + public async Task<ServiceResult<List<CoursePreviewDto>>> GetAll(int tenantId, bool isTemplate = false) { var result = new ServiceResult<List<CoursePreviewDto>>(); var courses = await _context.Courses - .Where(x => x.TenantId == tenantId) + .Where(x => x.TenantId == tenantId + && x.IsTemplate == isTemplate) .ToListAsync(); var coursesDto = _mapper.Map<List<CoursePreviewDto>>(courses); result.Data = coursesDto; - return result; } - public async Task<ServiceResult<bool>> Modify(int courseId, CourseCreateDto courseDto) + public async Task<ServiceResult<bool>> Modify(int courseId, CourseModifyDto courseDto) { var result = new ServiceResult<bool>(); @@ -210,12 +226,10 @@ namespace Tsi1.BusinessLayer.Services return result; } - _mapper.Map(courseDto, course); - + _mapper.Map(courseDto, course); await _context.SaveChangesAsync(); result.Data = true; - return result; } @@ -233,11 +247,9 @@ namespace Tsi1.BusinessLayer.Services } _context.Courses.Remove(course); - await _context.SaveChangesAsync(); result.Data = course; - return result; } @@ -316,11 +328,9 @@ namespace Tsi1.BusinessLayer.Services } _context.ProfessorCourses.Remove(professorCourse); - await _context.SaveChangesAsync(); result.Data = true; - return result; } @@ -338,7 +348,6 @@ namespace Tsi1.BusinessLayer.Services var userDtos = _mapper.Map<List<UserPreviewDto>>(users); result.Data = userDtos; - return result; } @@ -366,5 +375,34 @@ namespace Tsi1.BusinessLayer.Services return result; } + + public async Task<ServiceResult<bool>> CreateFromTemplate(CourseTemplateCreateDto courseTemplate, int tenantId) + { + var result = new ServiceResult<bool>(); + + var course = await _context.Courses.AsNoTracking() + .Include(x => x.Sections) + .ThenInclude(x => x.SectionItems) + .ThenInclude(x => x.Forum) + .FirstOrDefaultAsync(x => + x.TenantId == tenantId + && x.IsTemplate + && x.Id == courseTemplate.CourseTemplateId); + + if (course == null) + { + result.HasError = true; + result.AddMessage(string.Format(ErrorMessages.CourseDoesNotExist, courseTemplate.CourseTemplateId)); + return result; + } + + var newCourse = _mapper.Map<Course>(course); + newCourse.Name = courseTemplate.Name; + + _context.Add(newCourse); + await _context.SaveChangesAsync(); + + return result; + } } } diff --git a/Tsi1.Api/Tsi1.DataLayer/Entities/Course.cs b/Tsi1.Api/Tsi1.DataLayer/Entities/Course.cs index 942858f..80c4291 100644 --- a/Tsi1.Api/Tsi1.DataLayer/Entities/Course.cs +++ b/Tsi1.Api/Tsi1.DataLayer/Entities/Course.cs @@ -16,6 +16,7 @@ namespace Tsi1.DataLayer.Entities public int Id { get; set; } public string Name { get; set; } public int TenantId { get; set; } + public bool IsTemplate { get; set; } public Tenant Tenant { get; set; } public ICollection<StudentCourse> StudentCourses { get; set; } diff --git a/Tsi1.Api/Tsi1.DataLayer/EntityConfiguration/CourseConfiguration.cs b/Tsi1.Api/Tsi1.DataLayer/EntityConfiguration/CourseConfiguration.cs index 4cea401..0676afd 100644 --- a/Tsi1.Api/Tsi1.DataLayer/EntityConfiguration/CourseConfiguration.cs +++ b/Tsi1.Api/Tsi1.DataLayer/EntityConfiguration/CourseConfiguration.cs @@ -20,6 +20,9 @@ namespace Tsi1.DataLayer.EntityConfiguration .IsRequired() .HasColumnType("character varying(50)"); + builder.Property(x => x.IsTemplate) + .IsRequired(); + builder.HasOne(x => x.Tenant) .WithMany(x => x.Courses) .HasForeignKey(x => x.TenantId); diff --git a/Tsi1.Api/Tsi1.DataLayer/Migrations/20201112213633_course-template.Designer.cs b/Tsi1.Api/Tsi1.DataLayer/Migrations/20201112213633_course-template.Designer.cs new file mode 100644 index 0000000..506ca64 --- /dev/null +++ b/Tsi1.Api/Tsi1.DataLayer/Migrations/20201112213633_course-template.Designer.cs @@ -0,0 +1,611 @@ +// <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("20201112213633_course-template")] + partial class coursetemplate + { + 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.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.File", 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>("Path") + .IsRequired() + .HasColumnType("character varying(1000)"); + + b.HasKey("Id"); + + b.HasIndex("Path") + .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<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.HasKey("Id"); + + b.HasIndex("FileId") + .IsUnique(); + + b.HasIndex("ForumId") + .IsUnique(); + + b.HasIndex("SectionId"); + + b.HasIndex("SectionItemTypeId"); + + 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<int>("Age") + .HasColumnType("integer"); + + 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.Tenant", 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("Tenants"); + }); + + modelBuilder.Entity("Tsi1.DataLayer.Entities.User", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + 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.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.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(); + }); + + 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.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/20201112213633_course-template.cs b/Tsi1.Api/Tsi1.DataLayer/Migrations/20201112213633_course-template.cs new file mode 100644 index 0000000..36d655a --- /dev/null +++ b/Tsi1.Api/Tsi1.DataLayer/Migrations/20201112213633_course-template.cs @@ -0,0 +1,23 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +namespace Tsi1.DataLayer.Migrations +{ + public partial class coursetemplate : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn<bool>( + name: "IsTemplate", + table: "Courses", + nullable: false, + defaultValue: false); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "IsTemplate", + table: "Courses"); + } + } +} diff --git a/Tsi1.Api/Tsi1.DataLayer/Migrations/Tsi1ContextModelSnapshot.cs b/Tsi1.Api/Tsi1.DataLayer/Migrations/Tsi1ContextModelSnapshot.cs index e661f62..e07d884 100644 --- a/Tsi1.Api/Tsi1.DataLayer/Migrations/Tsi1ContextModelSnapshot.cs +++ b/Tsi1.Api/Tsi1.DataLayer/Migrations/Tsi1ContextModelSnapshot.cs @@ -44,6 +44,9 @@ namespace Tsi1.DataLayer.Migrations .HasColumnType("integer") .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + b.Property<bool>("IsTemplate") + .HasColumnType("boolean"); + b.Property<string>("Name") .IsRequired() .HasColumnType("character varying(50)"); -- GitLab