Skip to content
Snippets Groups Projects
Commit 165c6239 authored by Lucca Santangelo Dodera's avatar Lucca Santangelo Dodera
Browse files

Merge branch 'multi-tenancy' into 'master'

Multi tenancy

See merge request !5
parents 518b6541 58a3061a
No related branches found
No related tags found
1 merge request!5Multi tenancy
Showing
with 277 additions and 27 deletions
......@@ -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();
}
}
}
......@@ -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);
......
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);
}
}
}
......@@ -16,5 +16,9 @@ namespace Tsi1.Api.Models
[Required]
[JsonPropertyName("password")]
public string Password { get; set; }
[Required]
[JsonPropertyName("tenantId")]
public int TenantId { get; set; }
}
}
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; }
}
}
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.Json.Serialization;
namespace Tsi1.BusinessLayer.Dtos
{
......
......@@ -13,5 +13,8 @@ namespace Tsi1.BusinessLayer.Dtos
public int ReceiverId { get; set; }
public string Content { get; set; }
[JsonIgnore]
public int TenantId { get; set; }
}
}
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; }
}
}
using System;
using System.Collections.Generic;
using System.Text;
namespace Tsi1.BusinessLayer.Dtos
{
public class ProfessorPreviewDto
{
public string IdentityCard { get; set; }
}
}
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; }
}
}
......@@ -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; }
}
}
......@@ -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; }
}
}
......@@ -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}'";
}
}
......@@ -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>();
}
}
}
......@@ -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);
}
}
......@@ -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);
}
}
......@@ -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);
......
......@@ -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);
}
}
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;
......
......@@ -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}";
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment