diff --git a/Tsi1.Api/Tsi1.Api/Controllers/CourseController.cs b/Tsi1.Api/Tsi1.Api/Controllers/CourseController.cs index 03c403f9a56ede02a157b37538f221bcf3c8f3fd..19b56f853a2c8cb1db658771f40e43ca5a466815 100644 --- a/Tsi1.Api/Tsi1.Api/Controllers/CourseController.cs +++ b/Tsi1.Api/Tsi1.Api/Controllers/CourseController.cs @@ -44,6 +44,10 @@ namespace Tsi1.Api.Controllers [HttpPost("Create")] public async Task<IActionResult> Create(CourseCreateDto newCourse) { + var tenantId = int.Parse(HttpContext.User.Claims.FirstOrDefault(x => x.Type == "TenantId").Value); + + newCourse.TenantId = tenantId; + var result = await _courseService.Create(newCourse); if (result.HasError) { @@ -52,5 +56,34 @@ namespace Tsi1.Api.Controllers return Ok(); } + + + [Authorize(Roles = UserTypes.Student)] + [HttpPost("Matriculate/{courseId}")] + public async Task<IActionResult> Matriculate(int courseId) + { + var userId = int.Parse(HttpContext.User.Claims.FirstOrDefault(x => x.Type == "Id").Value); + + var result = await _courseService.Matriculate(userId, courseId); + if (result.HasError) + { + return BadRequest(result.Message); + } + + return Ok(); + } + + [Authorize(Roles = UserTypes.FacultyAdmin)] + [HttpPost("AddProfessorToCourse")] + public async Task<IActionResult> AddProfessorToCourse(ProfessorCourseDto professorCourseDto) + { + var result = await _courseService.AddProfessorToCourse(professorCourseDto); + if (result.HasError) + { + return BadRequest(result.Message); + } + + return Ok(); + } } } diff --git a/Tsi1.Api/Tsi1.Api/Controllers/MessageController.cs b/Tsi1.Api/Tsi1.Api/Controllers/MessageController.cs index b6b03bff80a30dcc58a3874575190b331a4233df..6d3633d803fdd1d00d6d8d9d37ba1763707e74ec 100644 --- a/Tsi1.Api/Tsi1.Api/Controllers/MessageController.cs +++ b/Tsi1.Api/Tsi1.Api/Controllers/MessageController.cs @@ -29,7 +29,9 @@ namespace Tsi1.Api.Controllers { var userId = int.Parse(HttpContext.User.Claims.FirstOrDefault(x => x.Type == "Id").Value); - var result = await _messageService.GetMessages(userId, receiverId); + var tenantId = int.Parse(HttpContext.User.Claims.FirstOrDefault(x => x.Type == "TenantId").Value); + + var result = await _messageService.GetMessages(userId, receiverId, tenantId); if (result.HasError) { @@ -45,7 +47,10 @@ namespace Tsi1.Api.Controllers { var userId = int.Parse(HttpContext.User.Claims.FirstOrDefault(x => x.Type == "Id").Value); + var tenantId = int.Parse(HttpContext.User.Claims.FirstOrDefault(x => x.Type == "TenantId").Value); + newMessage.SenderId = userId; + newMessage.TenantId = tenantId; var result = await _messageService.Send(newMessage); diff --git a/Tsi1.Api/Tsi1.Api/Controllers/UserController.cs b/Tsi1.Api/Tsi1.Api/Controllers/UserController.cs index 21b277adb29c2e7e5a64bec7d1dd1c4d56c349ed..b1fb2775ccac22639321795130fadcddae79ffeb 100644 --- a/Tsi1.Api/Tsi1.Api/Controllers/UserController.cs +++ b/Tsi1.Api/Tsi1.Api/Controllers/UserController.cs @@ -1,4 +1,5 @@ using System; +using System.Linq; using System.Security.Claims; using System.Threading.Tasks; using Microsoft.AspNetCore.Authorization; @@ -31,7 +32,7 @@ namespace Tsi1.Api.Controllers [HttpPost("Login")] public async Task<IActionResult> Login(LoginRequest request) { - var result = await _userService.Authenticate(request.UserName, request.Password); + var result = await _userService.Authenticate(request.UserName, request.Password, request.TenantId); if (result.HasError) { @@ -44,6 +45,7 @@ namespace Tsi1.Api.Controllers { new Claim("Id", user.Id.ToString()), new Claim("Username", user.Username), + new Claim("TenantId", user.TenantId.ToString()), new Claim(ClaimTypes.Role, user.UserType.Name) }; @@ -62,6 +64,9 @@ namespace Tsi1.Api.Controllers [HttpPost("Register")] public async Task<IActionResult> Register(UserRegisterDto dto) { + var tenantId = int.Parse(HttpContext.User.Claims.FirstOrDefault(x => x.Type == "TenantId").Value); + dto.TenantId = tenantId; + var userTypeResult = await _userTypeService.GetById(dto.UserTypeId); if (userTypeResult.HasError) @@ -86,7 +91,23 @@ namespace Tsi1.Api.Controllers [HttpGet("GetAll")] public async Task<IActionResult> GetAll() { - var result = await _userService.GetAll(); + var tenantId = int.Parse(HttpContext.User.Claims.FirstOrDefault(x => x.Type == "TenantId").Value); + + var result = await _userService.GetAll(tenantId); + + if (result.HasError) + { + return BadRequest(result.Message); + } + + return Ok(result.Data); + } + + [Authorize(Roles = UserTypes.Student + ", " + UserTypes.Professor)] + [HttpGet("GetById/{userId}")] + public async Task<IActionResult> GetById(int userId) + { + var result = await _userService.GetById(userId); if (result.HasError) { @@ -95,5 +116,6 @@ namespace Tsi1.Api.Controllers return Ok(result.Data); } + } } diff --git a/Tsi1.Api/Tsi1.Api/Models/LoginRequest.cs b/Tsi1.Api/Tsi1.Api/Models/LoginRequest.cs index 96e87b18d03e7185430f760fb0a5c9caefe6611f..0ce83cfe5fb8a94cd72d654e67cf93019638fdd8 100644 --- a/Tsi1.Api/Tsi1.Api/Models/LoginRequest.cs +++ b/Tsi1.Api/Tsi1.Api/Models/LoginRequest.cs @@ -16,5 +16,9 @@ namespace Tsi1.Api.Models [Required] [JsonPropertyName("password")] public string Password { get; set; } + + [Required] + [JsonPropertyName("tenantId")] + public int TenantId { get; set; } } } diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Dtos/CourseCreateDto.cs b/Tsi1.Api/Tsi1.BusinessLayer/Dtos/CourseCreateDto.cs index ef582f9fa58c2f162524f00d267a04c789091325..ffd3608d231c078c29b2a555f4b20ae565bfeaa8 100644 --- a/Tsi1.Api/Tsi1.BusinessLayer/Dtos/CourseCreateDto.cs +++ b/Tsi1.Api/Tsi1.BusinessLayer/Dtos/CourseCreateDto.cs @@ -1,11 +1,15 @@ using System; using System.Collections.Generic; using System.Text; +using System.Text.Json.Serialization; namespace Tsi1.BusinessLayer.Dtos { public class CourseCreateDto { public string Name { get; set; } + + [JsonIgnore] + public int TenantId { get; set; } } } diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Dtos/ForumCreateDto.cs b/Tsi1.Api/Tsi1.BusinessLayer/Dtos/ForumCreateDto.cs index 2756562ff74849602f0f89d682c40384ea6d219f..b4ebbecf257f0cf9667d615450a776738d3bac0c 100644 --- a/Tsi1.Api/Tsi1.BusinessLayer/Dtos/ForumCreateDto.cs +++ b/Tsi1.Api/Tsi1.BusinessLayer/Dtos/ForumCreateDto.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Text; +using System.Text.Json.Serialization; namespace Tsi1.BusinessLayer.Dtos { diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Dtos/MessageCreateDto.cs b/Tsi1.Api/Tsi1.BusinessLayer/Dtos/MessageCreateDto.cs index 628b095fe51b156d84d73089fd18c79f9a1b9ff9..399bc0c012b0f37a93225778eb670c294e2ec90b 100644 --- a/Tsi1.Api/Tsi1.BusinessLayer/Dtos/MessageCreateDto.cs +++ b/Tsi1.Api/Tsi1.BusinessLayer/Dtos/MessageCreateDto.cs @@ -13,5 +13,8 @@ namespace Tsi1.BusinessLayer.Dtos public int ReceiverId { get; set; } public string Content { get; set; } + + [JsonIgnore] + public int TenantId { get; set; } } } diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Dtos/ProfessorCourseDto.cs b/Tsi1.Api/Tsi1.BusinessLayer/Dtos/ProfessorCourseDto.cs new file mode 100644 index 0000000000000000000000000000000000000000..d88467ecb8daea0661fc3555806d77e2c5b7c667 --- /dev/null +++ b/Tsi1.Api/Tsi1.BusinessLayer/Dtos/ProfessorCourseDto.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Tsi1.BusinessLayer.Dtos +{ + public class ProfessorCourseDto + { + public int UserId { get; set; } + + public int CourseId { get; set; } + } +} diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Dtos/ProfessorPreviewDto.cs b/Tsi1.Api/Tsi1.BusinessLayer/Dtos/ProfessorPreviewDto.cs new file mode 100644 index 0000000000000000000000000000000000000000..374a36a35db2c765c86ca2ac35d1322abee8e370 --- /dev/null +++ b/Tsi1.Api/Tsi1.BusinessLayer/Dtos/ProfessorPreviewDto.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Tsi1.BusinessLayer.Dtos +{ + public class ProfessorPreviewDto + { + public string IdentityCard { get; set; } + } +} diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Dtos/StudentPreviewDto.cs b/Tsi1.Api/Tsi1.BusinessLayer/Dtos/StudentPreviewDto.cs new file mode 100644 index 0000000000000000000000000000000000000000..e05efa4dfd93c73fd367a9f40f73540a46769708 --- /dev/null +++ b/Tsi1.Api/Tsi1.BusinessLayer/Dtos/StudentPreviewDto.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Tsi1.BusinessLayer.Dtos +{ + public class StudentPreviewDto + { + public string IdentityCard { get; set; } + + public int Age { get; set; } + } +} diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Dtos/UserPreviewDto.cs b/Tsi1.Api/Tsi1.BusinessLayer/Dtos/UserPreviewDto.cs index bb62ecbee0d56efccbdf725ed267b51d08c31dd3..1c9804bd001f492f7f22dd84357ef2b56b528790 100644 --- a/Tsi1.Api/Tsi1.BusinessLayer/Dtos/UserPreviewDto.cs +++ b/Tsi1.Api/Tsi1.BusinessLayer/Dtos/UserPreviewDto.cs @@ -13,5 +13,9 @@ namespace Tsi1.BusinessLayer.Dtos public string FirstName { get; set; } public string LastName { get; set; } + + public StudentPreviewDto Student { get; set; } + + public ProfessorPreviewDto Professor { get; set; } } } diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Dtos/UserRegisterDto.cs b/Tsi1.Api/Tsi1.BusinessLayer/Dtos/UserRegisterDto.cs index 24616b382bf5c2ef36249f7b8af52e727fbcdae1..2cc5d2740edf2171ffa30d17e60389bc4290a17a 100644 --- a/Tsi1.Api/Tsi1.BusinessLayer/Dtos/UserRegisterDto.cs +++ b/Tsi1.Api/Tsi1.BusinessLayer/Dtos/UserRegisterDto.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Text; +using System.Text.Json.Serialization; namespace Tsi1.BusinessLayer.Dtos { @@ -28,6 +29,9 @@ namespace Tsi1.BusinessLayer.Dtos [Required] public string IdentityCard { get; set; } + [JsonIgnore] + public int TenantId { get; set; } + public int Age { get; set; } } } diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Helpers/ErrorMessages.cs b/Tsi1.Api/Tsi1.BusinessLayer/Helpers/ErrorMessages.cs index 0dbeef495bbeaf299bc1edeeeac6b1b653eaa583..880795c242b472b8ec7df424f0bc42ac33b789f7 100644 --- a/Tsi1.Api/Tsi1.BusinessLayer/Helpers/ErrorMessages.cs +++ b/Tsi1.Api/Tsi1.BusinessLayer/Helpers/ErrorMessages.cs @@ -9,13 +9,26 @@ namespace Tsi1.BusinessLayer.Helpers public const string UserDoesNotExist = "El usuario '{0}' no existe"; public const string IncorrectPassword = "Contraseña incorrecta"; public const string UserTypeDoesNotExist = "El tipo de usuario con id '{0}' no existe"; + public const string StudentDoesNotExist = "El estudiante con Id de usuario: '{0}' no existe"; + public const string StudentCourseAlreadyExists = "El estudiante '{0}' ya se encuentra matriculado en el curso '{1}'"; + public const string ProffesorDoesNotExist = "El profesor con Id de usuario: '{0}' no existe"; + public const string ProfessorCourseAlreadyExists = "El profesor '{0}' ya es docente del curso '{1}'"; + public const string ForumDoesNotExist = "El foro con id '{0}' no existe"; + public const string DuplicateForumName = "Ya existe un foro con nombre '{0}'"; + public const string DuplicateForumUser = "El usuario '{0}' ya se encuentra matriculado al foro '{1}'"; + + public const string PostDoesNotExist = "El post con id '{0}' no existe"; public const string PostMessageDoesNotExist = "El mensage con id '{0}' no existe"; public const string CannotConnectToSmtpServer = "No se pudo conectar al servidor SMTP"; 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 DuplicateCourseName = "Ya existe un curso con nombre '{0}'"; + } } diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Helpers/MappingProfile.cs b/Tsi1.Api/Tsi1.BusinessLayer/Helpers/MappingProfile.cs index 02ab611713d3080fc3ac99271dcd1787cde1518a..8fab13c1e816f8afb5cbf38d9981684b7555ab7b 100644 --- a/Tsi1.Api/Tsi1.BusinessLayer/Helpers/MappingProfile.cs +++ b/Tsi1.Api/Tsi1.BusinessLayer/Helpers/MappingProfile.cs @@ -22,7 +22,12 @@ namespace Tsi1.BusinessLayer.Helpers CreateMap<Message, MessageCreateDto>(); CreateMap<User, UserPreviewDto>(); CreateMap<User, UserRegisterDto>(); + CreateMap<Student, StudentPreviewDto>(); + CreateMap<Professor, ProfessorPreviewDto>(); + CreateMap<Course, CourseCreateDto>(); + CreateMap<Course, CoursePreviewDto>(); + CreateMap<ForumCreateDto, Forum>(); CreateMap<ForumPreviewDto, Forum>(); CreateMap<PostCreateDto, Post>(); @@ -33,6 +38,10 @@ namespace Tsi1.BusinessLayer.Helpers CreateMap<MessageCreateDto, Message>(); CreateMap<UserPreviewDto, User>(); CreateMap<UserRegisterDto, User>(); + CreateMap<StudentPreviewDto, Student>(); + CreateMap<ProfessorPreviewDto, Professor>(); + CreateMap<CourseCreateDto, Course>(); + CreateMap<CoursePreviewDto, Course>(); } } } diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Interfaces/ICourseService.cs b/Tsi1.Api/Tsi1.BusinessLayer/Interfaces/ICourseService.cs index df6907fa874b47fad6ce918464f4e0df12eb697e..082798fedb9a2cc7a9802f2266558a00e8111c8d 100644 --- a/Tsi1.Api/Tsi1.BusinessLayer/Interfaces/ICourseService.cs +++ b/Tsi1.Api/Tsi1.BusinessLayer/Interfaces/ICourseService.cs @@ -13,5 +13,9 @@ namespace Tsi1.BusinessLayer.Interfaces Task<ServiceResult<List<CoursePreviewDto>>> GetCoursePreviews(int userId, string userType); Task<ServiceResult<Course>> Create(CourseCreateDto newCourse); + + Task<ServiceResult<bool>> Matriculate(int userId, int courseId); + + Task<ServiceResult<bool>> AddProfessorToCourse(ProfessorCourseDto professorCourseDto); } } diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Interfaces/IEmailService.cs b/Tsi1.Api/Tsi1.BusinessLayer/Interfaces/IEmailService.cs index 4f68ea6c1064f22937bc6ded6f426c0f2829fab7..a97ea5c312cf5448689c731402cf293ea49ebca4 100644 --- a/Tsi1.Api/Tsi1.BusinessLayer/Interfaces/IEmailService.cs +++ b/Tsi1.Api/Tsi1.BusinessLayer/Interfaces/IEmailService.cs @@ -13,6 +13,6 @@ namespace Tsi1.BusinessLayer.Interfaces { Task<ServiceResult<bool>> SendEmailAsync(MimeMessage message); - Task<ServiceResult<bool>> NotifyNewPostOrMessage(PostCreateDto postCreateDto, List<string> users); + Task<ServiceResult<bool>> NotifyNewPostOrMessage(PostCreateDto postCreateDto, List<string> mails); } } diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Interfaces/IMessageService.cs b/Tsi1.Api/Tsi1.BusinessLayer/Interfaces/IMessageService.cs index 785b46134f790b90ade833746481cb16b914c3f5..f328cf436e1a44241407725b7a906837b61d6641 100644 --- a/Tsi1.Api/Tsi1.BusinessLayer/Interfaces/IMessageService.cs +++ b/Tsi1.Api/Tsi1.BusinessLayer/Interfaces/IMessageService.cs @@ -9,7 +9,7 @@ namespace Tsi1.BusinessLayer.Interfaces { public interface IMessageService { - Task<ServiceResult<List<MessagePreviewDto>>> GetMessages(int userId, int otherUserId); + Task<ServiceResult<List<MessagePreviewDto>>> GetMessages(int userId, int otherUserId, int tenantId); Task<ServiceResult<MessagePreviewDto>> Send(MessageCreateDto newMessage); diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Interfaces/IUserService.cs b/Tsi1.Api/Tsi1.BusinessLayer/Interfaces/IUserService.cs index 3e6742718302d55ca3993f3e526e8871efa5a5cd..ed780959cdca1def549471d306c0ad64ef0f7ac6 100644 --- a/Tsi1.Api/Tsi1.BusinessLayer/Interfaces/IUserService.cs +++ b/Tsi1.Api/Tsi1.BusinessLayer/Interfaces/IUserService.cs @@ -10,10 +10,12 @@ namespace Tsi1.BusinessLayer.Interfaces { public interface IUserService { - Task<ServiceResult<User>> Authenticate(string username, string password); + Task<ServiceResult<User>> Authenticate(string username, string password, int tenantId); Task<ServiceResult<User>> Create(UserRegisterDto dto, string type); - Task<ServiceResult<List<UserPreviewDto>>> GetAll(); + Task<ServiceResult<List<UserPreviewDto>>> GetAll(int tenantId); + + Task<ServiceResult<UserPreviewDto>> GetById(int userId); } } diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Services/CourseService.cs b/Tsi1.Api/Tsi1.BusinessLayer/Services/CourseService.cs index 05c175789cc8eb480a976c4db2076e781dcefa1d..4f8db3fc7b9bc1dfac00432c60f33e838baa8dc5 100644 --- a/Tsi1.Api/Tsi1.BusinessLayer/Services/CourseService.cs +++ b/Tsi1.Api/Tsi1.BusinessLayer/Services/CourseService.cs @@ -1,4 +1,6 @@ -using Microsoft.EntityFrameworkCore; +using AutoMapper; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.FileProviders; using System; using System.Collections.Generic; using System.Linq; @@ -16,23 +18,32 @@ namespace Tsi1.BusinessLayer.Services { private readonly Tsi1Context _context; - public CourseService(Tsi1Context context) + private readonly IMapper _mapper; + + public CourseService(Tsi1Context context, IMapper mapper) { _context = context; + _mapper = mapper; } public async Task<ServiceResult<Course>> Create(CourseCreateDto newCourse) { var result = new ServiceResult<Course>(); - var course = new Course() - { - Name = newCourse.Name - }; - + var course = _mapper.Map<Course>(newCourse); + _context.Courses.Add(course); - await _context.SaveChangesAsync(); - + try + { + await _context.SaveChangesAsync(); + } + catch (DbUpdateException) + { + result.HasError = true; + result.Message = string.Format(ErrorMessages.DuplicateCourseName, newCourse.Name); + return result; + } + result.Data = course; return result; } @@ -40,14 +51,23 @@ namespace Tsi1.BusinessLayer.Services public async Task<ServiceResult<List<CoursePreviewDto>>> GetCoursePreviews(int userId, string userType) { var result = new ServiceResult<List<CoursePreviewDto>>(); - result.Data = new List<CoursePreviewDto>(); var courses = new List<Course>(); + var user = await _context.Users.FirstOrDefaultAsync(x => x.Id == userId); + + if (user == null) + { + result.HasError = true; + result.Message = string.Format(ErrorMessages.UserDoesNotExist, userId); + return result; + } + if (userType == UserTypes.Student) { courses = await _context.StudentCourses .Include(x => x.Course) + .Where(x => x.StudentId == user.StudentId) .Select(x => x.Course) .ToListAsync(); } @@ -55,19 +75,104 @@ namespace Tsi1.BusinessLayer.Services { courses = await _context.ProfessorCourses .Include(x => x.Course) + .Where(x => x.ProfessorId == user.ProfessorId) .Select(x => x.Course) .ToListAsync(); } - foreach (var course in courses) + result.Data = _mapper.Map<List<CoursePreviewDto>>(courses); + + return result; + } + + public async Task<ServiceResult<bool>> Matriculate(int userId, int courseId) + { + var result = new ServiceResult<bool>(); + + var user = await _context.Users + .Include(x => x.Student) + .FirstOrDefaultAsync(x => x.Id == userId); + + if (user == null || user.Student == null) + { + result.HasError = true; + result.Message = string.Format(ErrorMessages.UserDoesNotExist, userId); + return result; + } + + var course = await _context.Courses.FirstOrDefaultAsync(x => x.Id == courseId); + + if (course == null) + { + result.HasError = true; + result.Message = string.Format(ErrorMessages.CourseDoesNotExist, courseId); + return result; + } + + var studentCourse = new StudentCourse { - var item = new CoursePreviewDto() - { - Id = course.Id, - Name = course.Name - }; + Course = course, + Student = user.Student + }; + + _context.StudentCourses.Add(studentCourse); + + try + { + await _context.SaveChangesAsync(); + } + catch (DbUpdateException) + { + result.HasError = true; + result.Message = string.Format(ErrorMessages.StudentCourseAlreadyExists, user.Username, course.Name); + return result; + } - result.Data.Add(item); + return result; + } + + public async Task<ServiceResult<bool>> AddProfessorToCourse(ProfessorCourseDto professorCourseDto) + { + var result = new ServiceResult<bool>(); + + var user = await _context.Users + .Include(x => x.Professor) + .FirstOrDefaultAsync(x => x.Id == professorCourseDto.UserId); + + if (user == null || user.Professor == null) + { + result.HasError = true; + result.Message = string.Format(ErrorMessages.UserDoesNotExist, user.Username); + return result; + } + + var course = await _context.Courses + .FirstOrDefaultAsync(x => x.Id == professorCourseDto.CourseId); + + if (course == null) + { + result.HasError = true; + result.Message = string.Format(ErrorMessages.CourseDoesNotExist, professorCourseDto.CourseId); + return result; + } + + var professorCourse = new ProfessorCourse + { + Course = course, + Professor = user.Professor + }; + + _context.ProfessorCourses.Add(professorCourse); + + try + { + await _context.SaveChangesAsync(); + } + catch (DbUpdateException) + { + result.HasError = true; + result.Message = string.Format(ErrorMessages.ProfessorCourseAlreadyExists, user.Username, course.Name); + return result; } return result; diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Services/EmailService.cs b/Tsi1.Api/Tsi1.BusinessLayer/Services/EmailService.cs index fad2cf7baa0a7069eb16970db32cc6b0f8efe24e..d00e398d81ef6e05d34547d90d87d5a6e11f7ffd 100644 --- a/Tsi1.Api/Tsi1.BusinessLayer/Services/EmailService.cs +++ b/Tsi1.Api/Tsi1.BusinessLayer/Services/EmailService.cs @@ -70,13 +70,13 @@ namespace Tsi1.BusinessLayer.Services return result; } - public async Task<ServiceResult<bool>> NotifyNewPostOrMessage(PostCreateDto postCreateDto, List<string> users) + public async Task<ServiceResult<bool>> NotifyNewPostOrMessage(PostCreateDto postCreateDto, List<string> mails) { var message = new MimeMessage(); - foreach (var user in users) + foreach (var mail in mails) { - message.To.Add(MailboxAddress.Parse(user)); + message.To.Add(MailboxAddress.Parse(mail)); } message.Subject = $"Nuevo Post: {postCreateDto.Title}"; diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Services/ForumService.cs b/Tsi1.Api/Tsi1.BusinessLayer/Services/ForumService.cs index 827cd381abf5ff45ff7dc02e1ab5029ae9e127f7..ec1a569579f6fcaf088a3e36df4554b901c0d5e3 100644 --- a/Tsi1.Api/Tsi1.BusinessLayer/Services/ForumService.cs +++ b/Tsi1.Api/Tsi1.BusinessLayer/Services/ForumService.cs @@ -33,7 +33,17 @@ namespace Tsi1.BusinessLayer.Services var forum = _mapper.Map<Forum>(newForum); _context.Forums.Add(forum); - await _context.SaveChangesAsync(); + + try + { + await _context.SaveChangesAsync(); + } + catch (DbUpdateException) + { + result.HasError = true; + result.Message = string.Format(ErrorMessages.DuplicateForumName, newForum.Name); + return result; + } result.Data = forum; @@ -102,6 +112,15 @@ namespace Tsi1.BusinessLayer.Services return result; } + var user = await _context.Users.FirstOrDefaultAsync(x => x.Id == userId); + + if (user == null) + { + result.HasError = true; + result.Message = string.Format(ErrorMessages.UserDoesNotExist, userId); + return result; + } + var forumUser = new ForumUser { ForumId = forumId, @@ -110,7 +129,16 @@ namespace Tsi1.BusinessLayer.Services _context.ForumUsers.Add(forumUser); - await _context.SaveChangesAsync(); + try + { + await _context.SaveChangesAsync(); + } + catch (DbUpdateException) + { + result.HasError = true; + result.Message = string.Format(ErrorMessages.DuplicateForumUser, user.Username, forum.Name); + return result; + } return result; } diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Services/MessageService.cs b/Tsi1.Api/Tsi1.BusinessLayer/Services/MessageService.cs index eab3cb3f4a2440d25007d09237e542219de54096..b49bf792f6777608c45c0f28b1fa3b06f750b23e 100644 --- a/Tsi1.Api/Tsi1.BusinessLayer/Services/MessageService.cs +++ b/Tsi1.Api/Tsi1.BusinessLayer/Services/MessageService.cs @@ -28,14 +28,14 @@ namespace Tsi1.BusinessLayer.Services _mapper = mapper; } - public async Task<ServiceResult<List<MessagePreviewDto>>> GetMessages(int userId, int otherUserId) + public async Task<ServiceResult<List<MessagePreviewDto>>> GetMessages(int userId, int otherUserId, int tenantId) { var result = new ServiceResult<List<MessagePreviewDto>>(); var sort = Builders<Message>.Sort.Ascending("Date"); - var messages = await _messages.Find(m => (m.SenderId == userId && m.ReceiverId == otherUserId) - || (m.SenderId == otherUserId && m.ReceiverId == userId)) + var messages = await _messages.Find(m => (m.SenderId == userId && m.ReceiverId == otherUserId && m.TenantId == tenantId) + || (m.SenderId == otherUserId && m.ReceiverId == userId && m.TenantId == tenantId)) .Sort(sort) .ToListAsync(); diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Services/PostMessageService.cs b/Tsi1.Api/Tsi1.BusinessLayer/Services/PostMessageService.cs index 067a3317b0b92812470a91b85d613ef5266e440a..5385c44c7f4934315f71647f334d1f15b64ae58a 100644 --- a/Tsi1.Api/Tsi1.BusinessLayer/Services/PostMessageService.cs +++ b/Tsi1.Api/Tsi1.BusinessLayer/Services/PostMessageService.cs @@ -45,7 +45,8 @@ namespace Tsi1.BusinessLayer.Services { var result = new ServiceResult<PostMessage>(); - var postMessage = await _context.PostMessages.FirstOrDefaultAsync(x => x.Id == postMessageId); + var postMessage = await _context.PostMessages + .FirstOrDefaultAsync(x => x.Id == postMessageId); if (postMessage == null) { diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Services/UserService.cs b/Tsi1.Api/Tsi1.BusinessLayer/Services/UserService.cs index e824af21ada188ab0a3221025a1959230a1135ef..b38e807990555358a68b41e281e3131b7865be78 100644 --- a/Tsi1.Api/Tsi1.BusinessLayer/Services/UserService.cs +++ b/Tsi1.Api/Tsi1.BusinessLayer/Services/UserService.cs @@ -25,13 +25,13 @@ namespace Tsi1.BusinessLayer.Services _mapper = mapper; } - public async Task<ServiceResult<User>> Authenticate(string username, string password) + public async Task<ServiceResult<User>> Authenticate(string username, string password, int tenantId) { var result = new ServiceResult<User>(); var user = await _context.Users .Include(x => x.UserType) - .FirstOrDefaultAsync(x => x.Username == username); + .FirstOrDefaultAsync(x => x.Username == username && x.TenantId == tenantId); if (user == null) { @@ -56,22 +56,15 @@ namespace Tsi1.BusinessLayer.Services { var result = new ServiceResult<User>(); - var user = new User() - { - UserTypeId = dto.UserTypeId, - Username = dto.Username, - Password = dto.Password, - Email = dto.Email, - FirstName = dto.FirstName, - LastName = dto.LastName - }; + var user = _mapper.Map<User>(dto); if (type == UserTypes.Student) { user.Student = new Student() { IdentityCard = dto.IdentityCard, - Age = dto.Age + Age = dto.Age, + TenantId = dto.TenantId }; } @@ -79,7 +72,8 @@ namespace Tsi1.BusinessLayer.Services { user.Professor = new Professor() { - IdentityCard = dto.IdentityCard + IdentityCard = dto.IdentityCard, + TenantId = dto.TenantId }; } @@ -90,12 +84,12 @@ namespace Tsi1.BusinessLayer.Services return result; } - public async Task<ServiceResult<List<UserPreviewDto>>> GetAll() + public async Task<ServiceResult<List<UserPreviewDto>>> GetAll(int tenantId) { var result = new ServiceResult<List<UserPreviewDto>>(); var users = await _context.Users - .Where(x => x.UserType.Name != UserTypes.FacultyAdmin) + .Where(x => x.UserType.Name != UserTypes.FacultyAdmin && x.TenantId == tenantId) .ToListAsync(); var usersDto = _mapper.Map<List<UserPreviewDto>>(users); @@ -104,5 +98,44 @@ namespace Tsi1.BusinessLayer.Services return result; } + + public async Task<ServiceResult<UserPreviewDto>> GetById(int userId) + { + var result = new ServiceResult<UserPreviewDto>(); + + var user = await _context.Users + .Include(x => x.UserType) + .Include(x => x.Student) + .Include(x => x.Professor) + .FirstOrDefaultAsync(x => x.Id == userId); + + if (user == null) + { + result.HasError = true; + result.Message = string.Format(ErrorMessages.UserDoesNotExist, userId); + return result; + } + + var userType = user.UserType.Name; + + if (userType == UserTypes.Student && user.Student == null) + { + result.HasError = true; + result.Message = string.Format(ErrorMessages.StudentDoesNotExist, userId); + return result; + } + else if(userType == UserTypes.Professor && user.Professor == null) + { + result.HasError = true; + result.Message = string.Format(ErrorMessages.ProffesorDoesNotExist, userId); + return result; + } + + var userDto = _mapper.Map<UserPreviewDto>(user); + + result.Data = userDto; + + return result; + } } } diff --git a/Tsi1.Api/Tsi1.DataLayer/Entities/Course.cs b/Tsi1.Api/Tsi1.DataLayer/Entities/Course.cs index c2ee29e9f389e639bb6e0602e86689d371eba172..0f4f050705ec5081ef0cd43de7f76b59f259d269 100644 --- a/Tsi1.Api/Tsi1.DataLayer/Entities/Course.cs +++ b/Tsi1.Api/Tsi1.DataLayer/Entities/Course.cs @@ -14,8 +14,13 @@ namespace Tsi1.DataLayer.Entities } public int Id { get; set; } + public string Name { get; set; } + public int TenantId { get; set; } + + public Tenant Tenant { get; set; } + public ICollection<StudentCourse> StudentCourses { get; set; } public ICollection<ProfessorCourse> ProfessorCourses { get; set; } public ICollection<Forum> Forums { get; set; } diff --git a/Tsi1.Api/Tsi1.DataLayer/Entities/Message.cs b/Tsi1.Api/Tsi1.DataLayer/Entities/Message.cs index 4925699629ad1863a4860433900dd189ea8d5fc7..76a37fc52f27639504a9b0b328beb1e457a032a1 100644 --- a/Tsi1.Api/Tsi1.DataLayer/Entities/Message.cs +++ b/Tsi1.Api/Tsi1.DataLayer/Entities/Message.cs @@ -18,7 +18,9 @@ namespace Tsi1.DataLayer.Entities public string Content { get; set; } - public DateTime Date { get; set; } + public DateTime Date { get; set; } + + public int TenantId { get; set; } } } diff --git a/Tsi1.Api/Tsi1.DataLayer/Entities/PostMessage.cs b/Tsi1.Api/Tsi1.DataLayer/Entities/PostMessage.cs index 0e73c2ab6ea02ae3122df9a739f404022360cc2b..93638335a61d8b925e4ef49ffe44476e58f6db47 100644 --- a/Tsi1.Api/Tsi1.DataLayer/Entities/PostMessage.cs +++ b/Tsi1.Api/Tsi1.DataLayer/Entities/PostMessage.cs @@ -13,11 +13,10 @@ namespace Tsi1.DataLayer.Entities public DateTime Date { get; set; } public int UserId { get; set; } - - public User User { get; set; } - + public int PostId { get; set; } public Post Post { get; set; } + public User User { get; set; } } } diff --git a/Tsi1.Api/Tsi1.DataLayer/Entities/Professor.cs b/Tsi1.Api/Tsi1.DataLayer/Entities/Professor.cs index a095017f2316ce399aa783be02564ac58fc19a48..9fb5aeea36d7d4ffb999782b0b339f2125e48410 100644 --- a/Tsi1.Api/Tsi1.DataLayer/Entities/Professor.cs +++ b/Tsi1.Api/Tsi1.DataLayer/Entities/Professor.cs @@ -12,8 +12,12 @@ namespace Tsi1.DataLayer.Entities } public int Id { get; set; } + public string IdentityCard { get; set; } + public int TenantId { get; set; } + + public Tenant Tenant { get; set; } public User User { get; set; } public ICollection<ProfessorCourse> ProfessorCourses { get; set; } } diff --git a/Tsi1.Api/Tsi1.DataLayer/Entities/Student.cs b/Tsi1.Api/Tsi1.DataLayer/Entities/Student.cs index acc85724b189d884047106a3d7423a138d5c639e..2688e376d376fd5b435f4f0be41fcec95c3dc2f0 100644 --- a/Tsi1.Api/Tsi1.DataLayer/Entities/Student.cs +++ b/Tsi1.Api/Tsi1.DataLayer/Entities/Student.cs @@ -12,9 +12,14 @@ namespace Tsi1.DataLayer.Entities } public int Id { get; set; } + public string IdentityCard { get; set; } + public int Age { get; set; } + public int TenantId { get; set; } + + public Tenant Tenant { get; set; } public User User { get; set; } public ICollection<StudentCourse> StudentCourses { get; set; } } diff --git a/Tsi1.Api/Tsi1.DataLayer/Entities/Tenant.cs b/Tsi1.Api/Tsi1.DataLayer/Entities/Tenant.cs new file mode 100644 index 0000000000000000000000000000000000000000..ce807be9044482303da464874681b0f0b4814d67 --- /dev/null +++ b/Tsi1.Api/Tsi1.DataLayer/Entities/Tenant.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Tsi1.DataLayer.Entities +{ + public class Tenant + { + public Tenant() + { + Courses = new HashSet<Course>(); + Professors = new HashSet<Professor>(); + Students = new HashSet<Student>(); + Users = new HashSet<User>(); + } + + public int Id { get; set; } + + public string Name { get; set; } + + public ICollection<Course> Courses { get; set; } + public ICollection<Professor> Professors { get; set; } + public ICollection<Student> Students { get; set; } + public ICollection<User> Users { get; set; } + } +} diff --git a/Tsi1.Api/Tsi1.DataLayer/Entities/User.cs b/Tsi1.Api/Tsi1.DataLayer/Entities/User.cs index dd7e8041f4af07d4d4fc0da1289bc83989cea95f..a62c4662edc5a781040ab78d454b33875ebb76d3 100644 --- a/Tsi1.Api/Tsi1.DataLayer/Entities/User.cs +++ b/Tsi1.Api/Tsi1.DataLayer/Entities/User.cs @@ -14,15 +14,26 @@ namespace Tsi1.DataLayer.Entities } public int Id { get; set; } + public int UserTypeId { get; set; } + public int? StudentId { get; set; } + public int? ProfessorId { get; set; } + public string Username { get; set; } + public string Password { get; set; } + public string FirstName { get; set; } + public string LastName { get; set; } + public string Email { get; set; } + public int TenantId { get; set; } + + public Tenant Tenant { get; set; } public UserType UserType { get; set; } public Student Student { get; set; } public Professor Professor { get; set; } diff --git a/Tsi1.Api/Tsi1.DataLayer/EntityConfiguration/CourseConfiguration.cs b/Tsi1.Api/Tsi1.DataLayer/EntityConfiguration/CourseConfiguration.cs index 2bec81eac60a7426e67afd8bba3392d9cf17c89c..4cea40149d552d51d4c6fab8bc3d4ae20e5b3b48 100644 --- a/Tsi1.Api/Tsi1.DataLayer/EntityConfiguration/CourseConfiguration.cs +++ b/Tsi1.Api/Tsi1.DataLayer/EntityConfiguration/CourseConfiguration.cs @@ -13,12 +13,16 @@ namespace Tsi1.DataLayer.EntityConfiguration { builder.HasKey(x => x.Id); - builder.HasIndex(x => x.Name) + builder.HasIndex(x => new { x.Name, x.TenantId }) .IsUnique(); builder.Property(x => x.Name) .IsRequired() .HasColumnType("character varying(50)"); + + builder.HasOne(x => x.Tenant) + .WithMany(x => x.Courses) + .HasForeignKey(x => x.TenantId); } } } diff --git a/Tsi1.Api/Tsi1.DataLayer/EntityConfiguration/ForumConfiguration.cs b/Tsi1.Api/Tsi1.DataLayer/EntityConfiguration/ForumConfiguration.cs index 0007d57ee4625c7756efa828488bb9034a6fb2bc..ac2d37069880b40303ee5208d896a1b3e1ed968e 100644 --- a/Tsi1.Api/Tsi1.DataLayer/EntityConfiguration/ForumConfiguration.cs +++ b/Tsi1.Api/Tsi1.DataLayer/EntityConfiguration/ForumConfiguration.cs @@ -14,7 +14,7 @@ namespace Tsi1.DataLayer.EntityConfiguration { builder.HasKey(x => x.Id); - builder.HasIndex(x => new { x.CourseId, x.Name }) + builder.HasIndex(x => new { x.CourseId, x.Name}) .IsUnique(); builder.Property(x => x.Name) diff --git a/Tsi1.Api/Tsi1.DataLayer/EntityConfiguration/PostConfiguration.cs b/Tsi1.Api/Tsi1.DataLayer/EntityConfiguration/PostConfiguration.cs index 6635726cf454e1d916ff57627c04e9e90927f73e..9ae3c716e0baa8b5d6b0367655cde6c275cb6c49 100644 --- a/Tsi1.Api/Tsi1.DataLayer/EntityConfiguration/PostConfiguration.cs +++ b/Tsi1.Api/Tsi1.DataLayer/EntityConfiguration/PostConfiguration.cs @@ -14,7 +14,7 @@ namespace Tsi1.DataLayer.EntityConfiguration { builder.HasKey(x => x.Id); - builder.HasIndex(x => new { x.ForumId, x.Title }) + builder.HasIndex(x => new { x.ForumId, x.Title}) .IsUnique(); builder.Property(x => x.Title) diff --git a/Tsi1.Api/Tsi1.DataLayer/EntityConfiguration/ProfessorConfiguration.cs b/Tsi1.Api/Tsi1.DataLayer/EntityConfiguration/ProfessorConfiguration.cs index 679dae301ad59a3b95baaf17c70661b3926f00b9..47de03f75c540dda0c5cae76e37c88c9276c614b 100644 --- a/Tsi1.Api/Tsi1.DataLayer/EntityConfiguration/ProfessorConfiguration.cs +++ b/Tsi1.Api/Tsi1.DataLayer/EntityConfiguration/ProfessorConfiguration.cs @@ -13,12 +13,16 @@ namespace Tsi1.DataLayer.EntityConfiguration { builder.HasKey(x => x.Id); - builder.HasIndex(x => x.IdentityCard) + builder.HasIndex(x => new { x.IdentityCard, x.TenantId }) .IsUnique(); builder.Property(x => x.IdentityCard) .IsRequired() .HasColumnType("character varying(50)"); + + builder.HasOne(x => x.Tenant) + .WithMany(x => x.Professors) + .HasForeignKey(x => x.TenantId); } } } diff --git a/Tsi1.Api/Tsi1.DataLayer/EntityConfiguration/StudentConfiguration.cs b/Tsi1.Api/Tsi1.DataLayer/EntityConfiguration/StudentConfiguration.cs index a7877ace1f806e899748ba2d436186b7dad33de4..7e841dbb8df245e655c401ea5894362f10993a95 100644 --- a/Tsi1.Api/Tsi1.DataLayer/EntityConfiguration/StudentConfiguration.cs +++ b/Tsi1.Api/Tsi1.DataLayer/EntityConfiguration/StudentConfiguration.cs @@ -13,7 +13,7 @@ namespace Tsi1.DataLayer.EntityConfiguration { builder.HasKey(x => x.Id); - builder.HasIndex(x => x.IdentityCard) + builder.HasIndex(x => new { x.IdentityCard, x.TenantId }) .IsUnique(); builder.Property(x => x.IdentityCard) @@ -22,6 +22,10 @@ namespace Tsi1.DataLayer.EntityConfiguration builder.Property(x => x.Age) .IsRequired(); + + builder.HasOne(x => x.Tenant) + .WithMany(x => x.Students) + .HasForeignKey(x => x.TenantId); } } } diff --git a/Tsi1.Api/Tsi1.DataLayer/EntityConfiguration/TenantConfiguration.cs b/Tsi1.Api/Tsi1.DataLayer/EntityConfiguration/TenantConfiguration.cs new file mode 100644 index 0000000000000000000000000000000000000000..dd0e9a4dffd5495369e89509d2be3f48a39ad782 --- /dev/null +++ b/Tsi1.Api/Tsi1.DataLayer/EntityConfiguration/TenantConfiguration.cs @@ -0,0 +1,25 @@ +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 +{ + class TenantConfiguration : IEntityTypeConfiguration<Tenant> + { + public void Configure(EntityTypeBuilder<Tenant> builder) + { + builder.HasKey(x => x.Id); + + builder.HasIndex(x => x.Name) + .IsUnique(); + + builder.Property(x => x.Name) + .IsRequired() + .HasColumnType("character varying(50)"); + + } + } +} diff --git a/Tsi1.Api/Tsi1.DataLayer/EntityConfiguration/UserConfiguration.cs b/Tsi1.Api/Tsi1.DataLayer/EntityConfiguration/UserConfiguration.cs index eadf441d032c10cc45e2b2552d386af604262e26..c10f5609c2debb61c96c15d0ee45049a79dacb8c 100644 --- a/Tsi1.Api/Tsi1.DataLayer/EntityConfiguration/UserConfiguration.cs +++ b/Tsi1.Api/Tsi1.DataLayer/EntityConfiguration/UserConfiguration.cs @@ -13,7 +13,7 @@ namespace Tsi1.DataLayer.EntityConfiguration { builder.HasKey(x => x.Id); - builder.HasIndex(x => x.Username) + builder.HasIndex(x => new { x.Username, x.TenantId }) .IsUnique(); builder.Property(x => x.Username) @@ -43,6 +43,10 @@ namespace Tsi1.DataLayer.EntityConfiguration builder.HasOne(x => x.Professor) .WithOne(x => x.User) .HasForeignKey<User>(x => x.ProfessorId); + + builder.HasOne(x => x.Tenant) + .WithMany(x => x.Users) + .HasForeignKey(x => x.TenantId); } } } diff --git a/Tsi1.Api/Tsi1.DataLayer/Migrations/20201022010216_add-multy-tenancy.Designer.cs b/Tsi1.Api/Tsi1.DataLayer/Migrations/20201022010216_add-multy-tenancy.Designer.cs new file mode 100644 index 0000000000000000000000000000000000000000..61c250cfe0742eab60532524a5817db1d063c646 --- /dev/null +++ b/Tsi1.Api/Tsi1.DataLayer/Migrations/20201022010216_add-multy-tenancy.Designer.cs @@ -0,0 +1,489 @@ +// <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("20201022010216_add-multy-tenancy")] + partial class addmultytenancy + { + 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.Course", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + 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.Forum", 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(50)"); + + b.Property<int>("TenantId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.HasIndex("CourseId", "Name", "TenantId") + .IsUnique(); + + 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.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<int>("TenantId") + .HasColumnType("integer"); + + b.Property<string>("Title") + .IsRequired() + .HasColumnType("character varying(100)"); + + b.Property<int>("UserId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.HasIndex("UserId"); + + b.HasIndex("ForumId", "Title", "TenantId") + .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>("TenantId") + .HasColumnType("integer"); + + b.Property<int>("UserId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("PostId"); + + b.HasIndex("TenantId"); + + 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.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.Course", b => + { + b.HasOne("Tsi1.DataLayer.Entities.Tenant", "Tenant") + .WithMany("Courses") + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Tsi1.DataLayer.Entities.Forum", b => + { + b.HasOne("Tsi1.DataLayer.Entities.Course", "Course") + .WithMany("Forums") + .HasForeignKey("CourseId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Tsi1.DataLayer.Entities.Tenant", "Tenant") + .WithMany("Forums") + .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.Tenant", "Tenant") + .WithMany("Posts") + .HasForeignKey("TenantId") + .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.Tenant", "Tenant") + .WithMany("PostMessages") + .HasForeignKey("TenantId") + .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.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/20201022010216_add-multy-tenancy.cs b/Tsi1.Api/Tsi1.DataLayer/Migrations/20201022010216_add-multy-tenancy.cs new file mode 100644 index 0000000000000000000000000000000000000000..c205fcedc807c1e2d1422e3cf13fab4bb87c484d --- /dev/null +++ b/Tsi1.Api/Tsi1.DataLayer/Migrations/20201022010216_add-multy-tenancy.cs @@ -0,0 +1,373 @@ +using Microsoft.EntityFrameworkCore.Migrations; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +namespace Tsi1.DataLayer.Migrations +{ + public partial class addmultytenancy : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropIndex( + name: "IX_Users_Username", + table: "Users"); + + migrationBuilder.DropIndex( + name: "IX_Students_IdentityCard", + table: "Students"); + + migrationBuilder.DropIndex( + name: "IX_Professors_IdentityCard", + table: "Professors"); + + migrationBuilder.DropIndex( + name: "IX_Posts_ForumId_Title", + table: "Posts"); + + migrationBuilder.DropIndex( + name: "IX_Forums_CourseId_Name", + table: "Forums"); + + migrationBuilder.DropIndex( + name: "IX_Courses_Name", + table: "Courses"); + + migrationBuilder.AddColumn<int>( + name: "TenantId", + table: "Users", + nullable: false, + defaultValue: 0); + + migrationBuilder.AddColumn<int>( + name: "TenantId", + table: "Students", + nullable: false, + defaultValue: 0); + + migrationBuilder.AddColumn<int>( + name: "TenantId", + table: "Professors", + nullable: false, + defaultValue: 0); + + migrationBuilder.AddColumn<int>( + name: "TenantId", + table: "Posts", + nullable: false, + defaultValue: 0); + + migrationBuilder.AddColumn<int>( + name: "TenantId", + table: "PostMessages", + nullable: false, + defaultValue: 0); + + migrationBuilder.AddColumn<int>( + name: "TenantId", + table: "Forums", + nullable: false, + defaultValue: 0); + + migrationBuilder.AddColumn<int>( + name: "TenantId", + table: "Courses", + nullable: false, + defaultValue: 0); + + migrationBuilder.CreateTable( + name: "Tenants", + columns: table => new + { + Id = table.Column<int>(nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + Name = table.Column<string>(type: "character varying(50)", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Tenants", x => x.Id); + }); + + migrationBuilder.CreateIndex( + name: "IX_Users_TenantId", + table: "Users", + column: "TenantId"); + + migrationBuilder.CreateIndex( + name: "IX_Users_Username_TenantId", + table: "Users", + columns: new[] { "Username", "TenantId" }, + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_Students_TenantId", + table: "Students", + column: "TenantId"); + + migrationBuilder.CreateIndex( + name: "IX_Students_IdentityCard_TenantId", + table: "Students", + columns: new[] { "IdentityCard", "TenantId" }, + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_Professors_TenantId", + table: "Professors", + column: "TenantId"); + + migrationBuilder.CreateIndex( + name: "IX_Professors_IdentityCard_TenantId", + table: "Professors", + columns: new[] { "IdentityCard", "TenantId" }, + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_Posts_TenantId", + table: "Posts", + column: "TenantId"); + + migrationBuilder.CreateIndex( + name: "IX_Posts_ForumId_Title_TenantId", + table: "Posts", + columns: new[] { "ForumId", "Title", "TenantId" }, + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_PostMessages_TenantId", + table: "PostMessages", + column: "TenantId"); + + migrationBuilder.CreateIndex( + name: "IX_Forums_TenantId", + table: "Forums", + column: "TenantId"); + + migrationBuilder.CreateIndex( + name: "IX_Forums_CourseId_Name_TenantId", + table: "Forums", + columns: new[] { "CourseId", "Name", "TenantId" }, + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_Courses_TenantId", + table: "Courses", + column: "TenantId"); + + migrationBuilder.CreateIndex( + name: "IX_Courses_Name_TenantId", + table: "Courses", + columns: new[] { "Name", "TenantId" }, + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_Tenants_Name", + table: "Tenants", + column: "Name", + unique: true); + + migrationBuilder.AddForeignKey( + name: "FK_Courses_Tenants_TenantId", + table: "Courses", + column: "TenantId", + principalTable: "Tenants", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_Forums_Tenants_TenantId", + table: "Forums", + column: "TenantId", + principalTable: "Tenants", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_PostMessages_Tenants_TenantId", + table: "PostMessages", + column: "TenantId", + principalTable: "Tenants", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_Posts_Tenants_TenantId", + table: "Posts", + column: "TenantId", + principalTable: "Tenants", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_Professors_Tenants_TenantId", + table: "Professors", + column: "TenantId", + principalTable: "Tenants", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_Students_Tenants_TenantId", + table: "Students", + column: "TenantId", + principalTable: "Tenants", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_Users_Tenants_TenantId", + table: "Users", + column: "TenantId", + principalTable: "Tenants", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_Courses_Tenants_TenantId", + table: "Courses"); + + migrationBuilder.DropForeignKey( + name: "FK_Forums_Tenants_TenantId", + table: "Forums"); + + migrationBuilder.DropForeignKey( + name: "FK_PostMessages_Tenants_TenantId", + table: "PostMessages"); + + migrationBuilder.DropForeignKey( + name: "FK_Posts_Tenants_TenantId", + table: "Posts"); + + migrationBuilder.DropForeignKey( + name: "FK_Professors_Tenants_TenantId", + table: "Professors"); + + migrationBuilder.DropForeignKey( + name: "FK_Students_Tenants_TenantId", + table: "Students"); + + migrationBuilder.DropForeignKey( + name: "FK_Users_Tenants_TenantId", + table: "Users"); + + migrationBuilder.DropTable( + name: "Tenants"); + + migrationBuilder.DropIndex( + name: "IX_Users_TenantId", + table: "Users"); + + migrationBuilder.DropIndex( + name: "IX_Users_Username_TenantId", + table: "Users"); + + migrationBuilder.DropIndex( + name: "IX_Students_TenantId", + table: "Students"); + + migrationBuilder.DropIndex( + name: "IX_Students_IdentityCard_TenantId", + table: "Students"); + + migrationBuilder.DropIndex( + name: "IX_Professors_TenantId", + table: "Professors"); + + migrationBuilder.DropIndex( + name: "IX_Professors_IdentityCard_TenantId", + table: "Professors"); + + migrationBuilder.DropIndex( + name: "IX_Posts_TenantId", + table: "Posts"); + + migrationBuilder.DropIndex( + name: "IX_Posts_ForumId_Title_TenantId", + table: "Posts"); + + migrationBuilder.DropIndex( + name: "IX_PostMessages_TenantId", + table: "PostMessages"); + + migrationBuilder.DropIndex( + name: "IX_Forums_TenantId", + table: "Forums"); + + migrationBuilder.DropIndex( + name: "IX_Forums_CourseId_Name_TenantId", + table: "Forums"); + + migrationBuilder.DropIndex( + name: "IX_Courses_TenantId", + table: "Courses"); + + migrationBuilder.DropIndex( + name: "IX_Courses_Name_TenantId", + table: "Courses"); + + migrationBuilder.DropColumn( + name: "TenantId", + table: "Users"); + + migrationBuilder.DropColumn( + name: "TenantId", + table: "Students"); + + migrationBuilder.DropColumn( + name: "TenantId", + table: "Professors"); + + migrationBuilder.DropColumn( + name: "TenantId", + table: "Posts"); + + migrationBuilder.DropColumn( + name: "TenantId", + table: "PostMessages"); + + migrationBuilder.DropColumn( + name: "TenantId", + table: "Forums"); + + migrationBuilder.DropColumn( + name: "TenantId", + table: "Courses"); + + migrationBuilder.CreateIndex( + name: "IX_Users_Username", + table: "Users", + column: "Username", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_Students_IdentityCard", + table: "Students", + column: "IdentityCard", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_Professors_IdentityCard", + table: "Professors", + column: "IdentityCard", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_Posts_ForumId_Title", + table: "Posts", + columns: new[] { "ForumId", "Title" }, + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_Forums_CourseId_Name", + table: "Forums", + columns: new[] { "CourseId", "Name" }, + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_Courses_Name", + table: "Courses", + column: "Name", + unique: true); + } + } +} diff --git a/Tsi1.Api/Tsi1.DataLayer/Migrations/Tsi1ContextModelSnapshot.cs b/Tsi1.Api/Tsi1.DataLayer/Migrations/Tsi1ContextModelSnapshot.cs index 993f66e459effd11bb2dc0b80bf5af6f6a65213c..87302ae42f0421fb44c201b4575e0be6e7a4cdd3 100644 --- a/Tsi1.Api/Tsi1.DataLayer/Migrations/Tsi1ContextModelSnapshot.cs +++ b/Tsi1.Api/Tsi1.DataLayer/Migrations/Tsi1ContextModelSnapshot.cs @@ -30,9 +30,14 @@ namespace Tsi1.DataLayer.Migrations .IsRequired() .HasColumnType("character varying(50)"); + b.Property<int>("TenantId") + .HasColumnType("integer"); + b.HasKey("Id"); - b.HasIndex("Name") + b.HasIndex("TenantId"); + + b.HasIndex("Name", "TenantId") .IsUnique(); b.ToTable("Courses"); @@ -52,9 +57,14 @@ namespace Tsi1.DataLayer.Migrations .IsRequired() .HasColumnType("character varying(50)"); + b.Property<int>("TenantId") + .HasColumnType("integer"); + b.HasKey("Id"); - b.HasIndex("CourseId", "Name") + b.HasIndex("TenantId"); + + b.HasIndex("CourseId", "Name", "TenantId") .IsUnique(); b.ToTable("Forums"); @@ -88,6 +98,9 @@ namespace Tsi1.DataLayer.Migrations b.Property<int>("ForumId") .HasColumnType("integer"); + b.Property<int>("TenantId") + .HasColumnType("integer"); + b.Property<string>("Title") .IsRequired() .HasColumnType("character varying(100)"); @@ -97,9 +110,11 @@ namespace Tsi1.DataLayer.Migrations b.HasKey("Id"); + b.HasIndex("TenantId"); + b.HasIndex("UserId"); - b.HasIndex("ForumId", "Title") + b.HasIndex("ForumId", "Title", "TenantId") .IsUnique(); b.ToTable("Posts"); @@ -122,6 +137,9 @@ namespace Tsi1.DataLayer.Migrations b.Property<int>("PostId") .HasColumnType("integer"); + b.Property<int>("TenantId") + .HasColumnType("integer"); + b.Property<int>("UserId") .HasColumnType("integer"); @@ -129,6 +147,8 @@ namespace Tsi1.DataLayer.Migrations b.HasIndex("PostId"); + b.HasIndex("TenantId"); + b.HasIndex("UserId"); b.ToTable("PostMessages"); @@ -145,9 +165,14 @@ namespace Tsi1.DataLayer.Migrations .IsRequired() .HasColumnType("character varying(50)"); + b.Property<int>("TenantId") + .HasColumnType("integer"); + b.HasKey("Id"); - b.HasIndex("IdentityCard") + b.HasIndex("TenantId"); + + b.HasIndex("IdentityCard", "TenantId") .IsUnique(); b.ToTable("Professors"); @@ -182,9 +207,14 @@ namespace Tsi1.DataLayer.Migrations .IsRequired() .HasColumnType("character varying(50)"); + b.Property<int>("TenantId") + .HasColumnType("integer"); + b.HasKey("Id"); - b.HasIndex("IdentityCard") + b.HasIndex("TenantId"); + + b.HasIndex("IdentityCard", "TenantId") .IsUnique(); b.ToTable("Students"); @@ -205,6 +235,25 @@ namespace Tsi1.DataLayer.Migrations 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") @@ -234,6 +283,9 @@ namespace Tsi1.DataLayer.Migrations b.Property<int?>("StudentId") .HasColumnType("integer"); + b.Property<int>("TenantId") + .HasColumnType("integer"); + b.Property<int>("UserTypeId") .HasColumnType("integer"); @@ -249,9 +301,11 @@ namespace Tsi1.DataLayer.Migrations b.HasIndex("StudentId") .IsUnique(); + b.HasIndex("TenantId"); + b.HasIndex("UserTypeId"); - b.HasIndex("Username") + b.HasIndex("Username", "TenantId") .IsUnique(); b.ToTable("Users"); @@ -276,6 +330,15 @@ namespace Tsi1.DataLayer.Migrations b.ToTable("UserTypes"); }); + 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.Forum", b => { b.HasOne("Tsi1.DataLayer.Entities.Course", "Course") @@ -283,6 +346,12 @@ namespace Tsi1.DataLayer.Migrations .HasForeignKey("CourseId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); + + b.HasOne("Tsi1.DataLayer.Entities.Tenant", "Tenant") + .WithMany("Forums") + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); }); modelBuilder.Entity("Tsi1.DataLayer.Entities.ForumUser", b => @@ -308,6 +377,12 @@ namespace Tsi1.DataLayer.Migrations .OnDelete(DeleteBehavior.Cascade) .IsRequired(); + b.HasOne("Tsi1.DataLayer.Entities.Tenant", "Tenant") + .WithMany("Posts") + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + b.HasOne("Tsi1.DataLayer.Entities.User", "User") .WithMany("Posts") .HasForeignKey("UserId") @@ -323,6 +398,12 @@ namespace Tsi1.DataLayer.Migrations .OnDelete(DeleteBehavior.Cascade) .IsRequired(); + b.HasOne("Tsi1.DataLayer.Entities.Tenant", "Tenant") + .WithMany("PostMessages") + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + b.HasOne("Tsi1.DataLayer.Entities.User", "User") .WithMany("PostMessages") .HasForeignKey("UserId") @@ -330,6 +411,15 @@ namespace Tsi1.DataLayer.Migrations .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") @@ -345,6 +435,15 @@ namespace Tsi1.DataLayer.Migrations .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") @@ -370,6 +469,12 @@ namespace Tsi1.DataLayer.Migrations .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") diff --git a/Tsi1.Api/Tsi1.DataLayer/Tsi1Context.cs b/Tsi1.Api/Tsi1.DataLayer/Tsi1Context.cs index 1ed9f61517e498afaaa6aa2344c57856b49a5324..c9fb14f74a1844a4fdc09fb7a9dea866975c2430 100644 --- a/Tsi1.Api/Tsi1.DataLayer/Tsi1Context.cs +++ b/Tsi1.Api/Tsi1.DataLayer/Tsi1Context.cs @@ -19,6 +19,7 @@ namespace Tsi1.DataLayer public DbSet<Forum> Forums { get; set; } public DbSet<Post> Posts { get; set; } public DbSet<PostMessage> PostMessages { get; set; } + public DbSet<Tenant> Tenants { get; set; } public DbSet<ForumUser> ForumUsers { get; set; } @@ -36,6 +37,7 @@ namespace Tsi1.DataLayer modelBuilder.ApplyConfiguration(new ForumConfiguration()); modelBuilder.ApplyConfiguration(new PostConfiguration()); modelBuilder.ApplyConfiguration(new PostMessageConfiguration()); + modelBuilder.ApplyConfiguration(new TenantConfiguration()); modelBuilder.ApplyConfiguration(new ForumUserConfiguration()); } }