From 33ef0c6ad55e42fa9d838baa5d5294038bb37b4f Mon Sep 17 00:00:00 2001
From: Lucca Santangelo <luccasant95@gmail.com>
Date: Thu, 10 Dec 2020 20:19:16 -0300
Subject: [PATCH] course passwords

---
 .../Tsi1.Api/Controllers/CourseController.cs  |    6 +-
 .../Dtos/CourseCreateDto.cs                   |    2 +
 .../Dtos/CourseDetailDto.cs                   |    2 +
 .../Dtos/CourseMatriculateDto.cs              |   12 +
 .../Dtos/CourseModifyDto.cs                   |    2 +
 .../Helpers/ErrorMessages.cs                  |    1 +
 .../Interfaces/ICourseService.cs              |    2 +-
 .../Services/CourseService.cs                 |   15 +-
 Tsi1.Api/Tsi1.DataLayer/Entities/Course.cs    |    2 +
 .../CourseConfiguration.cs                    |    7 +
 ...20201210230756_course-password.Designer.cs | 1077 +++++++++++++++++
 .../20201210230756_course-password.cs         |   34 +
 .../Migrations/Tsi1ContextModelSnapshot.cs    |    7 +
 13 files changed, 1161 insertions(+), 8 deletions(-)
 create mode 100644 Tsi1.Api/Tsi1.BusinessLayer/Dtos/CourseMatriculateDto.cs
 create mode 100644 Tsi1.Api/Tsi1.DataLayer/Migrations/20201210230756_course-password.Designer.cs
 create mode 100644 Tsi1.Api/Tsi1.DataLayer/Migrations/20201210230756_course-password.cs

diff --git a/Tsi1.Api/Tsi1.Api/Controllers/CourseController.cs b/Tsi1.Api/Tsi1.Api/Controllers/CourseController.cs
index 5414320..06a6fea 100644
--- a/Tsi1.Api/Tsi1.Api/Controllers/CourseController.cs
+++ b/Tsi1.Api/Tsi1.Api/Controllers/CourseController.cs
@@ -60,8 +60,8 @@ namespace Tsi1.Api.Controllers
         }
 
         [Authorize(Roles = UserTypes.Student)]
-        [HttpPost("Matriculate/{courseId}")]
-        public async Task<IActionResult> Matriculate(int courseId)
+        [HttpPost("Matriculate")]
+        public async Task<IActionResult> Matriculate(CourseMatriculateDto courseMatriculateDto)
         {
             try
             {
@@ -74,7 +74,7 @@ namespace Tsi1.Api.Controllers
                     return BadRequest(response.Message);
                 }
 
-                var result = await _courseService.Matriculate(userId, courseId);
+                var result = await _courseService.Matriculate(userId, courseMatriculateDto);
                 if (result.HasError)
                 {
                     return BadRequest(result.Message);
diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Dtos/CourseCreateDto.cs b/Tsi1.Api/Tsi1.BusinessLayer/Dtos/CourseCreateDto.cs
index 97aae1c..9b3d5c2 100644
--- a/Tsi1.Api/Tsi1.BusinessLayer/Dtos/CourseCreateDto.cs
+++ b/Tsi1.Api/Tsi1.BusinessLayer/Dtos/CourseCreateDto.cs
@@ -9,6 +9,8 @@ namespace Tsi1.BusinessLayer.Dtos
     {
         public string Name { get; set; }
         public bool IsTemplate { get; set; }
+        public bool HasPassword { get; set; }
+        public string Password { get; set; }
         public List<SectionCreateDto> Sections { get; set; }
 
         [JsonIgnore]
diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Dtos/CourseDetailDto.cs b/Tsi1.Api/Tsi1.BusinessLayer/Dtos/CourseDetailDto.cs
index 2aacbde..32a5f1e 100644
--- a/Tsi1.Api/Tsi1.BusinessLayer/Dtos/CourseDetailDto.cs
+++ b/Tsi1.Api/Tsi1.BusinessLayer/Dtos/CourseDetailDto.cs
@@ -9,6 +9,8 @@ namespace Tsi1.BusinessLayer.Dtos
         public int Id { get; set; }
         public string Name { get; set; }
         public int TenantId { get; set; }
+        public bool HasPassword { get; set; }
+        public string Password { get; set; }
         public List<SectionDetailDto> Sections { get; set; }
     }
 }
diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Dtos/CourseMatriculateDto.cs b/Tsi1.Api/Tsi1.BusinessLayer/Dtos/CourseMatriculateDto.cs
new file mode 100644
index 0000000..febda73
--- /dev/null
+++ b/Tsi1.Api/Tsi1.BusinessLayer/Dtos/CourseMatriculateDto.cs
@@ -0,0 +1,12 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Tsi1.BusinessLayer.Dtos
+{
+    public class CourseMatriculateDto
+    {
+        public int CourseId { get; set; }
+        public string Password { get; set; }
+    }
+}
diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Dtos/CourseModifyDto.cs b/Tsi1.Api/Tsi1.BusinessLayer/Dtos/CourseModifyDto.cs
index fe5599c..9047a83 100644
--- a/Tsi1.Api/Tsi1.BusinessLayer/Dtos/CourseModifyDto.cs
+++ b/Tsi1.Api/Tsi1.BusinessLayer/Dtos/CourseModifyDto.cs
@@ -6,6 +6,8 @@ namespace Tsi1.BusinessLayer.Dtos
     {
         public string Name { get; set; }
         public bool IsTemplate { get; set; }
+        public bool HasPassword { get; set; }
+        public string Password { get; set; }
 
         [JsonIgnore]
         public int TenantId { get; set; }
diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Helpers/ErrorMessages.cs b/Tsi1.Api/Tsi1.BusinessLayer/Helpers/ErrorMessages.cs
index 6812a72..729cb7d 100644
--- a/Tsi1.Api/Tsi1.BusinessLayer/Helpers/ErrorMessages.cs
+++ b/Tsi1.Api/Tsi1.BusinessLayer/Helpers/ErrorMessages.cs
@@ -35,6 +35,7 @@ namespace Tsi1.BusinessLayer.Helpers
         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 CourseInvalidPassword = "Clave de matriculación incorrecta para el curso {0}";
 
         public const string TenantDoesNotExist = "La Facultad '{0}' no existe";
         public const string DuplicateTenantName = "Ya existe una Facultad con nombre '{0}'";
diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Interfaces/ICourseService.cs b/Tsi1.Api/Tsi1.BusinessLayer/Interfaces/ICourseService.cs
index 7aa31a8..cdcebaf 100644
--- a/Tsi1.Api/Tsi1.BusinessLayer/Interfaces/ICourseService.cs
+++ b/Tsi1.Api/Tsi1.BusinessLayer/Interfaces/ICourseService.cs
@@ -12,7 +12,7 @@ namespace Tsi1.BusinessLayer.Interfaces
 
         Task<ServiceResult<int>> Create(CourseCreateDto newCourse);
 
-        Task<ServiceResult<bool>> Matriculate(int userId, int courseId);
+        Task<ServiceResult<bool>> Matriculate(int userId, CourseMatriculateDto courseMatriculateDto);
 
         Task<ServiceResult<bool>> AddProfessorToCourse(ProfessorCourseDto professorCourseDto, int userId, string userType);
 
diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Services/CourseService.cs b/Tsi1.Api/Tsi1.BusinessLayer/Services/CourseService.cs
index 05a0fa9..b724a6c 100644
--- a/Tsi1.Api/Tsi1.BusinessLayer/Services/CourseService.cs
+++ b/Tsi1.Api/Tsi1.BusinessLayer/Services/CourseService.cs
@@ -93,7 +93,7 @@ namespace Tsi1.BusinessLayer.Services
             return result;
         }
 
-        public async Task<ServiceResult<bool>> Matriculate(int userId, int courseId)
+        public async Task<ServiceResult<bool>> Matriculate(int userId, CourseMatriculateDto courseMatriculateDto)
         {
             var result = new ServiceResult<bool>();
 
@@ -114,19 +114,19 @@ namespace Tsi1.BusinessLayer.Services
                         .ThenInclude(x => x.SectionItemType)
                     .ThenInclude(x => x.SectionItems)
                         .ThenInclude(x => x.Forum)
-                .FirstOrDefaultAsync(x => x.Id == courseId);
+                .FirstOrDefaultAsync(x => x.Id == courseMatriculateDto.CourseId);
 
             if (course == null)
             {
                 result.HasError = true;
-                result.Message = string.Format(ErrorMessages.CourseDoesNotExist, courseId);
+                result.Message = string.Format(ErrorMessages.CourseDoesNotExist, courseMatriculateDto.CourseId);
                 return result;
             }
 
             if (course.IsTemplate)
             {
                 result.HasError = true;
-                result.AddMessage(string.Format(ErrorMessages.CourseIsTemplate, courseId));
+                result.AddMessage(string.Format(ErrorMessages.CourseIsTemplate, courseMatriculateDto.CourseId));
                 return result;
             }
 
@@ -140,6 +140,13 @@ namespace Tsi1.BusinessLayer.Services
                 return result;
             }
 
+            if (course.HasPassword && (course.Password != courseMatriculateDto.Password))
+            {
+                result.HasError = true;
+                result.Message = string.Format(ErrorMessages.CourseInvalidPassword, course.Name);
+                return result;
+            }
+
             var automaticSubscriptionForums = course.Sections
                 .SelectMany(x => x.SectionItems)
                 .Where(x => x.SectionItemType.Name == SectionItemTypes.Forum)
diff --git a/Tsi1.Api/Tsi1.DataLayer/Entities/Course.cs b/Tsi1.Api/Tsi1.DataLayer/Entities/Course.cs
index c09ae3a..5775fe7 100644
--- a/Tsi1.Api/Tsi1.DataLayer/Entities/Course.cs
+++ b/Tsi1.Api/Tsi1.DataLayer/Entities/Course.cs
@@ -19,6 +19,8 @@ namespace Tsi1.DataLayer.Entities
         public string Name { get; set; }
         public int TenantId { get; set; }
         public bool IsTemplate { get; set; }
+        public bool HasPassword { get; set; }
+        public string Password { 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 0676afd..e2b10d2 100644
--- a/Tsi1.Api/Tsi1.DataLayer/EntityConfiguration/CourseConfiguration.cs
+++ b/Tsi1.Api/Tsi1.DataLayer/EntityConfiguration/CourseConfiguration.cs
@@ -23,6 +23,13 @@ namespace Tsi1.DataLayer.EntityConfiguration
             builder.Property(x => x.IsTemplate)
                 .IsRequired();
 
+            builder.Property(x => x.HasPassword)
+                .IsRequired();
+
+            builder.Property(x => x.Password)
+                .IsRequired()
+                .HasColumnType("character varying(200)");
+
             builder.HasOne(x => x.Tenant)
                 .WithMany(x => x.Courses)
                 .HasForeignKey(x => x.TenantId);
diff --git a/Tsi1.Api/Tsi1.DataLayer/Migrations/20201210230756_course-password.Designer.cs b/Tsi1.Api/Tsi1.DataLayer/Migrations/20201210230756_course-password.Designer.cs
new file mode 100644
index 0000000..d5f81e8
--- /dev/null
+++ b/Tsi1.Api/Tsi1.DataLayer/Migrations/20201210230756_course-password.Designer.cs
@@ -0,0 +1,1077 @@
+// <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("20201210230756_course-password")]
+    partial class coursepassword
+    {
+        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>("HasPassword")
+                        .HasColumnType("boolean");
+
+                    b.Property<bool>("IsTemplate")
+                        .HasColumnType("boolean");
+
+                    b.Property<string>("Name")
+                        .IsRequired()
+                        .HasColumnType("character varying(50)");
+
+                    b.Property<string>("Password")
+                        .IsRequired()
+                        .HasColumnType("character varying(200)");
+
+                    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.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.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/20201210230756_course-password.cs b/Tsi1.Api/Tsi1.DataLayer/Migrations/20201210230756_course-password.cs
new file mode 100644
index 0000000..6732c7a
--- /dev/null
+++ b/Tsi1.Api/Tsi1.DataLayer/Migrations/20201210230756_course-password.cs
@@ -0,0 +1,34 @@
+using Microsoft.EntityFrameworkCore.Migrations;
+
+namespace Tsi1.DataLayer.Migrations
+{
+    public partial class coursepassword : Migration
+    {
+        protected override void Up(MigrationBuilder migrationBuilder)
+        {
+            migrationBuilder.AddColumn<bool>(
+                name: "HasPassword",
+                table: "Courses",
+                nullable: false,
+                defaultValue: false);
+
+            migrationBuilder.AddColumn<string>(
+                name: "Password",
+                table: "Courses",
+                type: "character varying(200)",
+                nullable: false,
+                defaultValue: "");
+        }
+
+        protected override void Down(MigrationBuilder migrationBuilder)
+        {
+            migrationBuilder.DropColumn(
+                name: "HasPassword",
+                table: "Courses");
+
+            migrationBuilder.DropColumn(
+                name: "Password",
+                table: "Courses");
+        }
+    }
+}
diff --git a/Tsi1.Api/Tsi1.DataLayer/Migrations/Tsi1ContextModelSnapshot.cs b/Tsi1.Api/Tsi1.DataLayer/Migrations/Tsi1ContextModelSnapshot.cs
index f3afd58..9415937 100644
--- a/Tsi1.Api/Tsi1.DataLayer/Migrations/Tsi1ContextModelSnapshot.cs
+++ b/Tsi1.Api/Tsi1.DataLayer/Migrations/Tsi1ContextModelSnapshot.cs
@@ -154,6 +154,9 @@ namespace Tsi1.DataLayer.Migrations
                         .HasColumnType("integer")
                         .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
 
+                    b.Property<bool>("HasPassword")
+                        .HasColumnType("boolean");
+
                     b.Property<bool>("IsTemplate")
                         .HasColumnType("boolean");
 
@@ -161,6 +164,10 @@ namespace Tsi1.DataLayer.Migrations
                         .IsRequired()
                         .HasColumnType("character varying(50)");
 
+                    b.Property<string>("Password")
+                        .IsRequired()
+                        .HasColumnType("character varying(200)");
+
                     b.Property<int>("TenantId")
                         .HasColumnType("integer");
 
-- 
GitLab