diff --git a/Directory.Build.props b/Directory.Build.props index 208b791ca..134b7ea71 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,6 +1,6 @@ - preview + 8 diff --git a/HwProj.APIGateway/HwProj.APIGateway.API/Controllers/CoursesController.cs b/HwProj.APIGateway/HwProj.APIGateway.API/Controllers/CoursesController.cs index 17725e28a..10ded91fa 100644 --- a/HwProj.APIGateway/HwProj.APIGateway.API/Controllers/CoursesController.cs +++ b/HwProj.APIGateway/HwProj.APIGateway.API/Controllers/CoursesController.cs @@ -2,6 +2,7 @@ using System.Linq; using System.Net; using System.Threading.Tasks; +using HwProj.APIGateway.API.Filters; using HwProj.APIGateway.API.Models; using HwProj.AuthService.Client; using HwProj.CoursesService.Client; @@ -34,6 +35,7 @@ public async Task GetAllCourses() return result; } + [CourseDataFilter] [HttpGet("{courseId}")] [ProducesResponseType(typeof(CourseViewModel), (int)HttpStatusCode.OK)] public async Task GetCourseData(long courseId) diff --git a/HwProj.CoursesService/HwProj.CoursesService.API/Filters/CourseDataFilterAttribute.cs b/HwProj.APIGateway/HwProj.APIGateway.API/Filters/CourseDataFilterAttribute.cs similarity index 60% rename from HwProj.CoursesService/HwProj.CoursesService.API/Filters/CourseDataFilterAttribute.cs rename to HwProj.APIGateway/HwProj.APIGateway.API/Filters/CourseDataFilterAttribute.cs index e584f2a61..92a8db78e 100644 --- a/HwProj.CoursesService/HwProj.CoursesService.API/Filters/CourseDataFilterAttribute.cs +++ b/HwProj.APIGateway/HwProj.APIGateway.API/Filters/CourseDataFilterAttribute.cs @@ -1,19 +1,20 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using HwProj.Models; +using HwProj.Models.AuthService.DTO; using HwProj.Models.CoursesService.ViewModels; -using HwProj.Utils.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; -namespace HwProj.CoursesService.API.Filters +namespace HwProj.APIGateway.API.Filters { public class CourseDataFilterAttribute : ResultFilterAttribute { public override async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next) { - var userId = context.HttpContext.Request.GetUserIdFromHeader(); + var userId = context.HttpContext.User.FindFirst("_id").Value; if (userId == null) { @@ -22,21 +23,18 @@ public override async Task OnResultExecutionAsync(ResultExecutingContext context else { var result = context.Result as ObjectResult; - if (result?.Value is CourseDTO courseDto && !courseDto.MentorIds.Contains(userId)) + if (result?.Value is CourseViewModel courseViewModel && + courseViewModel.Mentors.All(mentor => mentor.UserId != userId)) { var currentDate = DateTimeUtils.GetMoscowNow(); - foreach (var homework in courseDto.Homeworks) + foreach (var homework in courseViewModel.Homeworks) { homework.Tasks = new List(homework.Tasks.Where(t => currentDate >= t.PublicationDate)); } - courseDto.CourseMates = courseDto.CourseMates - .Where(t => t.IsAccepted || t.StudentId == userId) - .ToArray(); - - courseDto.Groups = courseDto.Groups.Where(g => g.StudentsIds.Contains(userId)).ToArray(); + courseViewModel.NewStudents = Array.Empty(); } } diff --git a/HwProj.AuthService/HwProj.AuthService.API/Events/AdminRegisterEvent.cs b/HwProj.AuthService/HwProj.AuthService.API/Events/AdminRegisterEvent.cs deleted file mode 100644 index 09fc75942..000000000 --- a/HwProj.AuthService/HwProj.AuthService.API/Events/AdminRegisterEvent.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace HwProj.AuthService.API.Events -{ - public class AdminRegisterEvent : RegisterEvent - { - public AdminRegisterEvent(string userId, string email, string name, string surname = "", string middleName = "") - : base(userId, email, name, surname, middleName) - { - - } - } -} diff --git a/HwProj.AuthService/HwProj.AuthService.API/Events/StudentRegisterEvent.cs b/HwProj.AuthService/HwProj.AuthService.API/Events/StudentRegisterEvent.cs deleted file mode 100644 index 5c894d2b8..000000000 --- a/HwProj.AuthService/HwProj.AuthService.API/Events/StudentRegisterEvent.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace HwProj.AuthService.API.Events -{ - public class StudentRegisterEvent : RegisterEvent - { - public StudentRegisterEvent(string userId, string email, string name, string surname = "", string middleName = "") - : base(userId, email, name, surname, middleName) - { - - } - } -} diff --git a/HwProj.AuthService/HwProj.AuthService.API/RoleInitializer.cs b/HwProj.AuthService/HwProj.AuthService.API/RoleInitializer.cs index f3bcd0143..dd83433e4 100644 --- a/HwProj.AuthService/HwProj.AuthService.API/RoleInitializer.cs +++ b/HwProj.AuthService/HwProj.AuthService.API/RoleInitializer.cs @@ -1,6 +1,6 @@ using Microsoft.AspNetCore.Identity; using System.Threading.Tasks; -using HwProj.AuthService.API.Events; +using HwProj.Models.Events.AuthEvents; using HwProj.EventBus.Client.Interfaces; using HwProj.Models.Roles; using HwProj.Models.AuthService.ViewModels; diff --git a/HwProj.AuthService/HwProj.AuthService.API/Services/AccountService.cs b/HwProj.AuthService/HwProj.AuthService.API/Services/AccountService.cs index f65b5d28c..84ada40a1 100644 --- a/HwProj.AuthService/HwProj.AuthService.API/Services/AccountService.cs +++ b/HwProj.AuthService/HwProj.AuthService.API/Services/AccountService.cs @@ -5,7 +5,7 @@ using AutoMapper; using HwProj.AuthService.API.Extensions; using HwProj.Models.Roles; -using HwProj.AuthService.API.Events; +using HwProj.Models.Events.AuthEvents; using HwProj.EventBus.Client.Interfaces; using HwProj.Models.AuthService.DTO; using HwProj.Models.AuthService.ViewModels; diff --git a/HwProj.Common/HwProj.Events/HwProj.Events.csproj b/HwProj.Common/HwProj.Events/HwProj.Events.csproj new file mode 100644 index 000000000..3ae664db1 --- /dev/null +++ b/HwProj.Common/HwProj.Events/HwProj.Events.csproj @@ -0,0 +1,13 @@ + + + + netcoreapp2.2 + HwProj.Events2 + + + + + + + + diff --git a/HwProj.Common/HwProj.HttpUtils/RequestHeaderBuilder.cs b/HwProj.Common/HwProj.HttpUtils/RequestHeaderBuilder.cs index 5ac4c68e2..cd1e3a995 100644 --- a/HwProj.Common/HwProj.HttpUtils/RequestHeaderBuilder.cs +++ b/HwProj.Common/HwProj.HttpUtils/RequestHeaderBuilder.cs @@ -7,7 +7,7 @@ public static class RequestHeaderBuilder { public static void TryAddUserId(this HttpRequestMessage request, IHttpContextAccessor httpContextAccessor) { - var userId = httpContextAccessor.HttpContext.User.FindFirst("_id"); + var userId = httpContextAccessor.HttpContext?.User.FindFirst("_id"); if (userId != null) request.Headers.Add("UserId", userId.Value); } } diff --git a/HwProj.Common/HwProj.Models/CoursesService/ViewModels/HomeworkTaskViewModels.cs b/HwProj.Common/HwProj.Models/CoursesService/ViewModels/HomeworkTaskViewModels.cs index 3535f5b10..d4508c4f2 100644 --- a/HwProj.Common/HwProj.Models/CoursesService/ViewModels/HomeworkTaskViewModels.cs +++ b/HwProj.Common/HwProj.Models/CoursesService/ViewModels/HomeworkTaskViewModels.cs @@ -29,6 +29,18 @@ public class HomeworkTaskViewModel public bool IsDeferred { get; set; } } + + public class HomeworkTaskDTO + { + public long Id { get; set; } + + public string Title { get; set; } + + public DateTime PublicationDate { get; set; } + + public DateTime? DeadlineDate { get; set; } + } + public class CreateTaskViewModel { [Required] diff --git a/HwProj.Common/HwProj.Models/Events/AuthEvents/AdminRegisterEvent.cs b/HwProj.Common/HwProj.Models/Events/AuthEvents/AdminRegisterEvent.cs new file mode 100644 index 000000000..e13ee52f8 --- /dev/null +++ b/HwProj.Common/HwProj.Models/Events/AuthEvents/AdminRegisterEvent.cs @@ -0,0 +1,15 @@ +using HwProj.EventBus.Client; + +namespace HwProj.Models.Events.AuthEvents +{ + public class AdminRegisterEvent : RegisterEvent + { + public AdminRegisterEvent(string userId, string email, string name, string surname = "", string middleName = "") + : base(userId, email, name, surname, middleName) + { + } + + public override string EventName => "AdminRegisterEvent"; + public override EventCategory Category => EventCategory.Users; + } +} diff --git a/HwProj.AuthService/HwProj.AuthService.API/Events/InviteLecturerEvent.cs b/HwProj.Common/HwProj.Models/Events/AuthEvents/InviteLecturerEvent.cs similarity index 50% rename from HwProj.AuthService/HwProj.AuthService.API/Events/InviteLecturerEvent.cs rename to HwProj.Common/HwProj.Models/Events/AuthEvents/InviteLecturerEvent.cs index 345d6cc40..dcc4a4b0a 100644 --- a/HwProj.AuthService/HwProj.AuthService.API/Events/InviteLecturerEvent.cs +++ b/HwProj.Common/HwProj.Models/Events/AuthEvents/InviteLecturerEvent.cs @@ -1,10 +1,12 @@ using HwProj.EventBus.Client; -namespace HwProj.AuthService.API.Events +namespace HwProj.Models.Events.AuthEvents { public class InviteLecturerEvent : Event { public string UserId { get; set; } public string UserEmail { get; set; } + public override string EventName => "InviteLecturerEvent"; + public override EventCategory Category => EventCategory.Users; } } diff --git a/HwProj.AuthService/HwProj.AuthService.API/Events/PasswordRecoveryEvent.cs b/HwProj.Common/HwProj.Models/Events/AuthEvents/PasswordRecoveryEvent.cs similarity index 62% rename from HwProj.AuthService/HwProj.AuthService.API/Events/PasswordRecoveryEvent.cs rename to HwProj.Common/HwProj.Models/Events/AuthEvents/PasswordRecoveryEvent.cs index c751d6521..d394c7616 100644 --- a/HwProj.AuthService/HwProj.AuthService.API/Events/PasswordRecoveryEvent.cs +++ b/HwProj.Common/HwProj.Models/Events/AuthEvents/PasswordRecoveryEvent.cs @@ -1,6 +1,6 @@ using HwProj.EventBus.Client; -namespace HwProj.AuthService.API.Events +namespace HwProj.Models.Events.AuthEvents { public class PasswordRecoveryEvent : Event { @@ -9,5 +9,7 @@ public class PasswordRecoveryEvent : Event public string Surname { get; set; } public string Email { get; set; } public string Token { get; set; } + public override string EventName => "PasswordRecoveryEvent"; + public override EventCategory Category => EventCategory.Users; } } diff --git a/HwProj.AuthService/HwProj.AuthService.API/Events/RegisterEvent.cs b/HwProj.Common/HwProj.Models/Events/AuthEvents/RegisterEvent.cs similarity index 93% rename from HwProj.AuthService/HwProj.AuthService.API/Events/RegisterEvent.cs rename to HwProj.Common/HwProj.Models/Events/AuthEvents/RegisterEvent.cs index c2625e5ba..9aba0fac7 100644 --- a/HwProj.AuthService/HwProj.AuthService.API/Events/RegisterEvent.cs +++ b/HwProj.Common/HwProj.Models/Events/AuthEvents/RegisterEvent.cs @@ -1,6 +1,6 @@ using HwProj.EventBus.Client; -namespace HwProj.AuthService.API.Events +namespace HwProj.Models.Events.AuthEvents { public abstract class RegisterEvent : Event { diff --git a/HwProj.Common/HwProj.Models/Events/AuthEvents/StudentRegisterEvent.cs b/HwProj.Common/HwProj.Models/Events/AuthEvents/StudentRegisterEvent.cs new file mode 100644 index 000000000..acf4a6c0b --- /dev/null +++ b/HwProj.Common/HwProj.Models/Events/AuthEvents/StudentRegisterEvent.cs @@ -0,0 +1,16 @@ +using HwProj.EventBus.Client; + +namespace HwProj.Models.Events.AuthEvents +{ + public class StudentRegisterEvent : RegisterEvent + { + public StudentRegisterEvent(string userId, string email, string name, string surname = "", + string middleName = "") + : base(userId, email, name, surname, middleName) + { + } + + public override string EventName => "StudentRegisterEvent"; + public override EventCategory Category => EventCategory.Users; + } +} diff --git a/HwProj.Common/HwProj.Models/Events/CourseEvents/AddOrUpdateEvent.cs b/HwProj.Common/HwProj.Models/Events/CourseEvents/AddOrUpdateEvent.cs new file mode 100644 index 000000000..71dc62940 --- /dev/null +++ b/HwProj.Common/HwProj.Models/Events/CourseEvents/AddOrUpdateEvent.cs @@ -0,0 +1,19 @@ +using HwProj.EventBus.Client; +using HwProj.Models.CoursesService.ViewModels; + +namespace HwProj.Models.Events.CourseEvents +{ + public class AddOrUpdateTaskEvent : Event + { + public bool IsUpdate { get; set; } + public long TaskId { get; set; } + public override string EventName => "UpdateTaskEvent"; + public override EventCategory Category => EventCategory.Tasks; + + public AddOrUpdateTaskEvent(long taskId, bool isUpdate) + { + TaskId = taskId; + IsUpdate = isUpdate; + } + } +} \ No newline at end of file diff --git a/HwProj.Common/HwProj.Models/Events/CourseEvents/DeleteTaskEvent.cs b/HwProj.Common/HwProj.Models/Events/CourseEvents/DeleteTaskEvent.cs new file mode 100644 index 000000000..102cc4353 --- /dev/null +++ b/HwProj.Common/HwProj.Models/Events/CourseEvents/DeleteTaskEvent.cs @@ -0,0 +1,16 @@ +using HwProj.EventBus.Client; + +namespace HwProj.Models.Events.CourseEvents +{ + public class DeleteTaskEvent : Event + { + public long TaskId { get; set; } + public override string EventName => "DeleteTaskEvent"; + public override EventCategory Category => EventCategory.Tasks; + + public DeleteTaskEvent(long taskId) + { + TaskId = taskId; + } + } +} diff --git a/HwProj.CoursesService/HwProj.CoursesService.API/Events/LecturerAcceptToCourseEvent.cs b/HwProj.Common/HwProj.Models/Events/CourseEvents/LecturerAcceptToCourseEvent.cs similarity index 60% rename from HwProj.CoursesService/HwProj.CoursesService.API/Events/LecturerAcceptToCourseEvent.cs rename to HwProj.Common/HwProj.Models/Events/CourseEvents/LecturerAcceptToCourseEvent.cs index 163af8672..6165affa6 100644 --- a/HwProj.CoursesService/HwProj.CoursesService.API/Events/LecturerAcceptToCourseEvent.cs +++ b/HwProj.Common/HwProj.Models/Events/CourseEvents/LecturerAcceptToCourseEvent.cs @@ -1,6 +1,6 @@ using HwProj.EventBus.Client; -namespace HwProj.CoursesService.API.Events +namespace HwProj.Models.Events.CourseEvents { public class LecturerAcceptToCourseEvent : Event { @@ -8,5 +8,8 @@ public class LecturerAcceptToCourseEvent : Event public string CourseName { get; set; } public string MentorIds { get; set; } public string StudentId { get; set; } + + public override string EventName => "AcceptToCourseEvent"; + public override EventCategory Category => EventCategory.Courses; } } diff --git a/HwProj.CoursesService/HwProj.CoursesService.API/Events/LecturerInvitedToCourseEvent.cs b/HwProj.Common/HwProj.Models/Events/CourseEvents/LecturerInvitedToCourseEvent.cs similarity index 59% rename from HwProj.CoursesService/HwProj.CoursesService.API/Events/LecturerInvitedToCourseEvent.cs rename to HwProj.Common/HwProj.Models/Events/CourseEvents/LecturerInvitedToCourseEvent.cs index 31be36694..2908ef306 100644 --- a/HwProj.CoursesService/HwProj.CoursesService.API/Events/LecturerInvitedToCourseEvent.cs +++ b/HwProj.Common/HwProj.Models/Events/CourseEvents/LecturerInvitedToCourseEvent.cs @@ -1,6 +1,6 @@ using HwProj.EventBus.Client; -namespace HwProj.CoursesService.API.Events +namespace HwProj.Models.Events.CourseEvents { public class LecturerInvitedToCourseEvent : Event { @@ -8,5 +8,8 @@ public class LecturerInvitedToCourseEvent : Event public string CourseName { get; set; } public string MentorId { get; set; } public string MentorEmail { get; set; } + + public override string EventName => "LecturerInvitedToCourseEvent"; + public override EventCategory Category => EventCategory.Courses; } } diff --git a/HwProj.CoursesService/HwProj.CoursesService.API/Events/LecturerRejectToCourseEvent.cs b/HwProj.Common/HwProj.Models/Events/CourseEvents/LecturerRejectToCourseEvent.cs similarity index 56% rename from HwProj.CoursesService/HwProj.CoursesService.API/Events/LecturerRejectToCourseEvent.cs rename to HwProj.Common/HwProj.Models/Events/CourseEvents/LecturerRejectToCourseEvent.cs index 9386a6cb1..8db607e4f 100644 --- a/HwProj.CoursesService/HwProj.CoursesService.API/Events/LecturerRejectToCourseEvent.cs +++ b/HwProj.Common/HwProj.Models/Events/CourseEvents/LecturerRejectToCourseEvent.cs @@ -1,12 +1,14 @@ using HwProj.EventBus.Client; -namespace HwProj.CoursesService.API.Events +namespace HwProj.Models.Events.CourseEvents { public class LecturerRejectToCourseEvent : Event { public long CourseId { get; set; } public string CourseName { get; set; } - public string MentorIds { get; set; } public string StudentId { get; set; } + + public override string EventName => "RejectToCourseEvent"; + public override EventCategory Category => EventCategory.Courses; } } diff --git a/HwProj.CoursesService/HwProj.CoursesService.API/Events/NewCourseMateEvent.cs b/HwProj.Common/HwProj.Models/Events/CourseEvents/NewCourseMateEvent.cs similarity index 62% rename from HwProj.CoursesService/HwProj.CoursesService.API/Events/NewCourseMateEvent.cs rename to HwProj.Common/HwProj.Models/Events/CourseEvents/NewCourseMateEvent.cs index 747917731..b33b6a135 100644 --- a/HwProj.CoursesService/HwProj.CoursesService.API/Events/NewCourseMateEvent.cs +++ b/HwProj.Common/HwProj.Models/Events/CourseEvents/NewCourseMateEvent.cs @@ -1,6 +1,6 @@ using HwProj.EventBus.Client; -namespace HwProj.CoursesService.API.Events +namespace HwProj.Models.Events.CourseEvents { public class NewCourseMateEvent : Event { @@ -9,5 +9,8 @@ public class NewCourseMateEvent : Event public string MentorIds { get; set; } public string StudentId { get; set; } public bool IsAccepted { get; set; } + + public override string EventName => "NewCourseMateEvent"; + public override EventCategory Category => EventCategory.Courses; } -} \ No newline at end of file +} diff --git a/HwProj.CoursesService/HwProj.CoursesService.API/Events/NewHomeworkEvent.cs b/HwProj.Common/HwProj.Models/Events/CourseEvents/NewHomeworkEvent.cs similarity index 67% rename from HwProj.CoursesService/HwProj.CoursesService.API/Events/NewHomeworkEvent.cs rename to HwProj.Common/HwProj.Models/Events/CourseEvents/NewHomeworkEvent.cs index b78429c18..f2e80f155 100644 --- a/HwProj.CoursesService/HwProj.CoursesService.API/Events/NewHomeworkEvent.cs +++ b/HwProj.Common/HwProj.Models/Events/CourseEvents/NewHomeworkEvent.cs @@ -1,13 +1,16 @@ using HwProj.EventBus.Client; using HwProj.Models.CoursesService.ViewModels; -namespace HwProj.CoursesService.API.Events +namespace HwProj.Models.Events.CourseEvents { public class NewHomeworkEvent : Event { public string Homework { get; set; } public CourseDTO Course { get; set; } + public override string EventName => "NewHomeworkEvent"; + public override EventCategory Category => EventCategory.Homeworks; + public NewHomeworkEvent(string homework, CourseDTO course) { Homework = homework; diff --git a/HwProj.CoursesService/HwProj.CoursesService.API/Events/UpdateHomeworkEvent.cs b/HwProj.Common/HwProj.Models/Events/CourseEvents/UpdateHomeworkEvent.cs similarity index 68% rename from HwProj.CoursesService/HwProj.CoursesService.API/Events/UpdateHomeworkEvent.cs rename to HwProj.Common/HwProj.Models/Events/CourseEvents/UpdateHomeworkEvent.cs index 9045f256d..e867a5e27 100644 --- a/HwProj.CoursesService/HwProj.CoursesService.API/Events/UpdateHomeworkEvent.cs +++ b/HwProj.Common/HwProj.Models/Events/CourseEvents/UpdateHomeworkEvent.cs @@ -1,13 +1,16 @@ using HwProj.EventBus.Client; using HwProj.Models.CoursesService.ViewModels; -namespace HwProj.CoursesService.API.Events +namespace HwProj.Models.Events.CourseEvents { public class UpdateHomeworkEvent : Event { public HomeworkViewModel Homework { get; set; } public CourseDTO Course { get; set; } + public override string EventName => "UpdateHomeworkEvent"; + public override EventCategory Category => EventCategory.Homeworks; + public UpdateHomeworkEvent(HomeworkViewModel homework, CourseDTO course) { Homework = homework; diff --git a/HwProj.SolutionsService/HwProj.SolutionsService.API/Events/RateEvent.cs b/HwProj.Common/HwProj.Models/Events/SolutionEvents/RateEvent.cs similarity index 71% rename from HwProj.SolutionsService/HwProj.SolutionsService.API/Events/RateEvent.cs rename to HwProj.Common/HwProj.Models/Events/SolutionEvents/RateEvent.cs index 9a1d88091..ce041d443 100644 --- a/HwProj.SolutionsService/HwProj.SolutionsService.API/Events/RateEvent.cs +++ b/HwProj.Common/HwProj.Models/Events/SolutionEvents/RateEvent.cs @@ -2,13 +2,16 @@ using HwProj.Models.CoursesService.ViewModels; using HwProj.Models.SolutionsService; -namespace HwProj.SolutionsService.API.Events +namespace HwProj.Models.Events.SolutionEvents { public class RateEvent : Event { public HomeworkTaskViewModel Task { get; set; } public SolutionViewModel Solution { get; set; } + public override string EventName => "RateEvent"; + public override EventCategory Category => EventCategory.Solutions; + public RateEvent(HomeworkTaskViewModel task, SolutionViewModel solution) { Task = task; diff --git a/HwProj.SolutionsService/HwProj.SolutionsService.API/Events/StudentPassTaskEvent.cs b/HwProj.Common/HwProj.Models/Events/SolutionEvents/StudentPassTaskEvent.cs similarity index 66% rename from HwProj.SolutionsService/HwProj.SolutionsService.API/Events/StudentPassTaskEvent.cs rename to HwProj.Common/HwProj.Models/Events/SolutionEvents/StudentPassTaskEvent.cs index e9798b28d..438f1195a 100644 --- a/HwProj.SolutionsService/HwProj.SolutionsService.API/Events/StudentPassTaskEvent.cs +++ b/HwProj.Common/HwProj.Models/Events/SolutionEvents/StudentPassTaskEvent.cs @@ -3,7 +3,7 @@ using HwProj.Models.CoursesService.ViewModels; using HwProj.Models.SolutionsService; -namespace HwProj.SolutionsService.API.Events +namespace HwProj.Models.Events.SolutionEvents { public class StudentPassTaskEvent : Event { @@ -12,11 +12,15 @@ public class StudentPassTaskEvent : Event public AccountDataDto Student { get; set; } public HomeworkTaskViewModel Task { get; set; } - public StudentPassTaskEvent(CourseDTO course, SolutionViewModel solution, AccountDataDto student, HomeworkTaskViewModel task) + public override string EventName => "StudentPassTaskEvent"; + public override EventCategory Category => EventCategory.Solutions; + + public StudentPassTaskEvent(CourseDTO course, SolutionViewModel solution, AccountDataDto student, + HomeworkTaskViewModel task) { Course = course; Solution = solution; - Student= student; + Student = student; Task = task; } } diff --git a/HwProj.Common/HwProj.Models/HwProj.Models.csproj b/HwProj.Common/HwProj.Models/HwProj.Models.csproj index 0ec3918d8..ecab40b8c 100644 --- a/HwProj.Common/HwProj.Models/HwProj.Models.csproj +++ b/HwProj.Common/HwProj.Models/HwProj.Models.csproj @@ -10,15 +10,17 @@ - + + + diff --git a/HwProj.CoursesService/HwProj.CoursesService.API/ApplicationProfile.cs b/HwProj.CoursesService/HwProj.CoursesService.API/ApplicationProfile.cs index ab3954c03..55247cb2c 100644 --- a/HwProj.CoursesService/HwProj.CoursesService.API/ApplicationProfile.cs +++ b/HwProj.CoursesService/HwProj.CoursesService.API/ApplicationProfile.cs @@ -28,6 +28,7 @@ public ApplicationProfile() CreateMap() .ForMember("IsDeferred", cm => cm.MapFrom(g => DateTimeUtils.GetMoscowNow() < g.PublicationDate)); CreateMap().ReverseMap(); + CreateMap(); } } } diff --git a/HwProj.CoursesService/HwProj.CoursesService.API/Controllers/CoursesController.cs b/HwProj.CoursesService/HwProj.CoursesService.API/Controllers/CoursesController.cs index d3c6095f1..5d25c888f 100644 --- a/HwProj.CoursesService/HwProj.CoursesService.API/Controllers/CoursesController.cs +++ b/HwProj.CoursesService/HwProj.CoursesService.API/Controllers/CoursesController.cs @@ -43,8 +43,7 @@ public async Task GetAll() var courses = _mapper.Map(coursesFromDb).ToArray(); return courses; } - - [CourseDataFilter] + [HttpGet("{courseId}")] public async Task Get(long courseId) { @@ -53,8 +52,7 @@ public async Task Get(long courseId) return Ok(course); } - - [CourseDataFilter] + [HttpGet("getByTask/{taskId}")] public async Task GetByTask(long taskId) { @@ -122,8 +120,7 @@ public async Task RejectStudent(long courseId, [FromQuery] string ? Ok() as IActionResult : NotFound(); } - - [CourseDataFilter] + [HttpGet("userCourses")] public async Task GetUserCourses(string role) { diff --git a/HwProj.CoursesService/HwProj.CoursesService.API/Events/NewHomeworkTaskEvent.cs b/HwProj.CoursesService/HwProj.CoursesService.API/Events/NewHomeworkTaskEvent.cs deleted file mode 100644 index 3a5ed857a..000000000 --- a/HwProj.CoursesService/HwProj.CoursesService.API/Events/NewHomeworkTaskEvent.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System; -using HwProj.EventBus.Client; -using HwProj.Models.CoursesService.ViewModels; - -namespace HwProj.CoursesService.API.Events -{ - public class NewHomeworkTaskEvent : Event - { - public NewHomeworkTaskEvent(string taskTitle, long taskId, DateTime? deadline, CourseDTO course) - { - TaskTitle = taskTitle; - TaskId = taskId; - Deadline = deadline; - Course = course; - } - - public string TaskTitle { get; set; } - public long TaskId { get; set; } - public DateTime? Deadline { get; set; } - public CourseDTO Course { get; set; } - } -} diff --git a/HwProj.CoursesService/HwProj.CoursesService.API/Events/UpdateSolutionMaxRatingEvent.cs b/HwProj.CoursesService/HwProj.CoursesService.API/Events/UpdateSolutionMaxRatingEvent.cs deleted file mode 100644 index 59f77ce4c..000000000 --- a/HwProj.CoursesService/HwProj.CoursesService.API/Events/UpdateSolutionMaxRatingEvent.cs +++ /dev/null @@ -1,18 +0,0 @@ -using HwProj.EventBus.Client; - -namespace HwProj.CoursesService.API.Events -{ - public class UpdateSolutionMaxRatingEvent : Event - { - public long TaskId { get; set; } - public long SolutionId { get; set; } - public int MaxRating { get; set; } - - public UpdateSolutionMaxRatingEvent(long taskId, long solutionId, int rating) - { - TaskId = taskId; - MaxRating = rating; - SolutionId = solutionId; - } - } -} diff --git a/HwProj.CoursesService/HwProj.CoursesService.API/Events/UpdateTaskMaxRatingEvent.cs b/HwProj.CoursesService/HwProj.CoursesService.API/Events/UpdateTaskMaxRatingEvent.cs deleted file mode 100644 index 4f20de847..000000000 --- a/HwProj.CoursesService/HwProj.CoursesService.API/Events/UpdateTaskMaxRatingEvent.cs +++ /dev/null @@ -1,19 +0,0 @@ -using HwProj.EventBus.Client; -using HwProj.Models.CoursesService.ViewModels; - -namespace HwProj.CoursesService.API.Events -{ - public class UpdateTaskMaxRatingEvent : Event - { - public CourseDTO Course { get; set; } - public HomeworkTaskViewModel Task { get; set; } - public int MaxRating { get; set; } - - public UpdateTaskMaxRatingEvent(CourseDTO course, HomeworkTaskViewModel task, int rating) - { - Course = course; - Task = task; - MaxRating = rating; - } - } -} diff --git a/HwProj.CoursesService/HwProj.CoursesService.API/Services/CoursesService.cs b/HwProj.CoursesService/HwProj.CoursesService.API/Services/CoursesService.cs index e7034650b..dd969a283 100644 --- a/HwProj.CoursesService/HwProj.CoursesService.API/Services/CoursesService.cs +++ b/HwProj.CoursesService/HwProj.CoursesService.API/Services/CoursesService.cs @@ -3,7 +3,6 @@ using System.Threading.Tasks; using AutoMapper; using HwProj.AuthService.Client; -using HwProj.CoursesService.API.Events; using HwProj.CoursesService.API.Models; using HwProj.CoursesService.API.Repositories; using HwProj.CoursesService.API.Repositories.Groups; @@ -12,6 +11,7 @@ using HwProj.Models.CoursesService.ViewModels; using HwProj.Models.Roles; using Microsoft.EntityFrameworkCore; +using HwProj.Models.Events.CourseEvents; namespace HwProj.CoursesService.API.Services { @@ -189,7 +189,6 @@ public async Task RejectCourseMateAsync(long courseId, string studentId) { CourseId = courseId, CourseName = course.Name, - MentorIds = course.MentorIds, StudentId = studentId }); return true; diff --git a/HwProj.CoursesService/HwProj.CoursesService.API/Services/HomeworksService.cs b/HwProj.CoursesService/HwProj.CoursesService.API/Services/HomeworksService.cs index 2558e64fc..242b47744 100644 --- a/HwProj.CoursesService/HwProj.CoursesService.API/Services/HomeworksService.cs +++ b/HwProj.CoursesService/HwProj.CoursesService.API/Services/HomeworksService.cs @@ -3,9 +3,9 @@ using HwProj.CoursesService.API.Models; using HwProj.CoursesService.API.Repositories; using HwProj.EventBus.Client.Interfaces; -using HwProj.CoursesService.API.Events; using HwProj.Models; using HwProj.Models.CoursesService.ViewModels; +using HwProj.Models.Events.CourseEvents; namespace HwProj.CoursesService.API.Services { diff --git a/HwProj.CoursesService/HwProj.CoursesService.API/Services/TasksService.cs b/HwProj.CoursesService/HwProj.CoursesService.API/Services/TasksService.cs index e99ea1203..20071deaa 100644 --- a/HwProj.CoursesService/HwProj.CoursesService.API/Services/TasksService.cs +++ b/HwProj.CoursesService/HwProj.CoursesService.API/Services/TasksService.cs @@ -1,11 +1,10 @@ using System.Threading.Tasks; using AutoMapper; -using HwProj.CoursesService.API.Events; using HwProj.CoursesService.API.Models; using HwProj.CoursesService.API.Repositories; using HwProj.EventBus.Client.Interfaces; -using HwProj.Models; using HwProj.Models.CoursesService.ViewModels; +using HwProj.Models.Events.CourseEvents; namespace HwProj.CoursesService.API.Services { @@ -19,7 +18,8 @@ public class TasksService : ITasksService private readonly ICoursesService _coursesService; public TasksService(ITasksRepository tasksRepository, IEventBus eventBus, IMapper mapper, - ICoursesRepository coursesRepository, IHomeworksRepository homeworksRepository, ICoursesService coursesService) + ICoursesRepository coursesRepository, IHomeworksRepository homeworksRepository, + ICoursesService coursesService) { _tasksRepository = tasksRepository; _homeworksRepository = homeworksRepository; @@ -41,28 +41,30 @@ public async Task AddTaskAsync(long homeworkId, HomeworkTask task) var homework = await _homeworksRepository.GetAsync(task.HomeworkId); var course = await _coursesRepository.GetWithCourseMatesAsync(homework.CourseId); var courseModel = _mapper.Map(course); - + var taskModel = _mapper.Map(task); var taskId = await _tasksRepository.AddAsync(task); - if (task.PublicationDate <= DateTimeUtils.GetMoscowNow()) - _eventBus.Publish(new NewHomeworkTaskEvent(task.Title, taskId, task.DeadlineDate, courseModel)); + _eventBus.Publish(new AddOrUpdateTaskEvent(taskId, false)); return taskId; } public async Task DeleteTaskAsync(long taskId) { + _eventBus.Publish(new DeleteTaskEvent(taskId)); await _tasksRepository.DeleteAsync(taskId); } public async Task UpdateTaskAsync(long taskId, HomeworkTask update) { var task = await _tasksRepository.GetAsync(taskId); - var taskModel = _mapper.Map(task); var homework = await _homeworksRepository.GetAsync(task.HomeworkId); var course = await _coursesRepository.GetWithCourseMatesAsync(homework.CourseId); var courseModel = _mapper.Map(course); - _eventBus.Publish(new UpdateTaskMaxRatingEvent(courseModel, taskModel, update.MaxRating)); + var previousTaskModel = _mapper.Map(task); + var newTaskModel = _mapper.Map(update); + + _eventBus.Publish(new AddOrUpdateTaskEvent(taskId, true)); await _tasksRepository.UpdateAsync(taskId, t => new HomeworkTask() { diff --git a/HwProj.CoursesService/HwProj.CoursesService.API/Startup.cs b/HwProj.CoursesService/HwProj.CoursesService.API/Startup.cs index 15f05f2cd..a73057041 100644 --- a/HwProj.CoursesService/HwProj.CoursesService.API/Startup.cs +++ b/HwProj.CoursesService/HwProj.CoursesService.API/Startup.cs @@ -1,4 +1,6 @@ -using HwProj.AuthService.Client; +using System; +using System.Threading.Channels; +using HwProj.AuthService.Client; using HwProj.CoursesService.API.Filters; using HwProj.CoursesService.API.Models; using HwProj.CoursesService.API.Repositories; @@ -25,6 +27,7 @@ public Startup(IConfiguration configuration) public void ConfigureServices(IServiceCollection services) { var connectionString = ConnectionString.GetConnectionString(Configuration); + services.AddDbContext(options => options.UseSqlServer(connectionString)); services.AddScoped(); services.AddScoped(); diff --git a/HwProj.EventBus/HwProj.EventBus.Client/Event.cs b/HwProj.EventBus/HwProj.EventBus.Client/Event.cs index 8a62cbd96..0da3278a4 100644 --- a/HwProj.EventBus/HwProj.EventBus.Client/Event.cs +++ b/HwProj.EventBus/HwProj.EventBus.Client/Event.cs @@ -3,21 +3,29 @@ namespace HwProj.EventBus.Client { - public class Event + public enum EventCategory { - [JsonProperty] - public Guid Id { get; set; } + Users, + Courses, + Homeworks, + Tasks, + Solutions + } - [JsonProperty] - public DateTime CreationData { get; set; } + public abstract class Event + { + [JsonProperty] public Guid Id { get; set; } + [JsonProperty] public DateTime CreationData { get; set; } + public abstract string EventName { get; } + public abstract EventCategory Category { get; } - public Event() + protected Event() { Id = Guid.NewGuid(); CreationData = DateTime.UtcNow; } - public Event(Guid id, DateTime data) + protected Event(Guid id, DateTime data) { Id = id; CreationData = data; diff --git a/HwProj.EventBus/HwProj.EventBus.Client/HwProj.EventBus.Client.csproj b/HwProj.EventBus/HwProj.EventBus.Client/HwProj.EventBus.Client.csproj index 7932fcc9d..01fb17fd8 100644 --- a/HwProj.EventBus/HwProj.EventBus.Client/HwProj.EventBus.Client.csproj +++ b/HwProj.EventBus/HwProj.EventBus.Client/HwProj.EventBus.Client.csproj @@ -18,9 +18,6 @@ - - - - + diff --git a/HwProj.EventBus/HwProj.EventBus.Tests/TestEvent.cs b/HwProj.EventBus/HwProj.EventBus.Tests/TestEvent.cs index 62acb15b3..7420174e7 100644 --- a/HwProj.EventBus/HwProj.EventBus.Tests/TestEvent.cs +++ b/HwProj.EventBus/HwProj.EventBus.Tests/TestEvent.cs @@ -8,10 +8,13 @@ public class TestEvent : Event public int NewPrice { get; set; } - public TestEvent(int newPrice, int oldPrice) + public TestEvent(int newPrice, int oldPrice) { OldPrice = oldPrice; NewPrice = newPrice; } + + public override string EventName => "TestEvent"; + public override EventCategory Category => EventCategory.Courses; } } diff --git a/HwProj.NotificationsService/HwProj.NotificationsService.API/Controllers/NotificationSettingsController.cs b/HwProj.NotificationsService/HwProj.NotificationsService.API/Controllers/NotificationSettingsController.cs index e916bb5fa..b2e93f502 100644 --- a/HwProj.NotificationsService/HwProj.NotificationsService.API/Controllers/NotificationSettingsController.cs +++ b/HwProj.NotificationsService/HwProj.NotificationsService.API/Controllers/NotificationSettingsController.cs @@ -1,6 +1,5 @@ using System.Threading.Tasks; using HwProj.Models.NotificationsService; -using HwProj.NotificationsService.API.Models; using HwProj.NotificationsService.API.Repositories; using Microsoft.AspNetCore.Mvc; diff --git a/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/AddOrUpdateTaskEventHandler.cs b/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/AddOrUpdateTaskEventHandler.cs new file mode 100644 index 000000000..1c404336a --- /dev/null +++ b/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/AddOrUpdateTaskEventHandler.cs @@ -0,0 +1,102 @@ +using System; +using System.Diagnostics.Tracing; +using System.Linq; +using System.Threading.Tasks; +using AutoMapper; +using HwProj.AuthService.Client; +using HwProj.CoursesService.Client; +using HwProj.EventBus.Client.Interfaces; +using HwProj.Models.Events.CourseEvents; +using HwProj.Models.NotificationsService; +using HwProj.NotificationsService.API.Jobs; +using HwProj.NotificationsService.API.Repositories; +using HwProj.NotificationsService.API.Services; +using Microsoft.Extensions.Configuration; + +namespace HwProj.NotificationsService.API.EventHandlers +{ + public class AddOrUpdateTaskEventHandler : EventHandlerBase + { + private readonly ICoursesServiceClient _coursesServiceClient; + private readonly INotificationsRepository _notificationRepository; + private readonly IAuthServiceClient _authServiceClient; + private readonly IMapper _mapper; + private readonly IConfigurationSection _configuration; + private readonly IEmailService _emailService; + private readonly IScheduleJobsRepository _scheduleJobsRepository; + + public AddOrUpdateTaskEventHandler( + ICoursesServiceClient coursesServiceClient, + INotificationsRepository notificationRepository, + IMapper mapper, + IAuthServiceClient authServiceClient, + IConfiguration configuration, + IEmailService emailService, + IScheduleJobsRepository scheduleJobsRepository) + { + _coursesServiceClient = coursesServiceClient; + _notificationRepository = notificationRepository; + _mapper = mapper; + _authServiceClient = authServiceClient; + _emailService = emailService; + _configuration = configuration.GetSection("Notification"); + _scheduleJobsRepository = scheduleJobsRepository; + } + + public override async Task HandleAsync(AddOrUpdateTaskEvent @event) + { + //TODO : ленивость не работает + var task = await _coursesServiceClient.GetTask(@event.TaskId); + + if (task.PublicationDate <= DateTime.UtcNow) + { + await AddNotificationsAsync(@event); + } + else if (@event.IsUpdate) + { + await EventHandlerExtensions.UpdateScheduleJobAsync(@event, @event.TaskId, + task.PublicationDate, () => AddNotificationsAsync(@event), _scheduleJobsRepository); + } + else + { + await EventHandlerExtensions.AddScheduleJobAsync(@event, @event.TaskId, + task.PublicationDate, () => AddNotificationsAsync(@event), _scheduleJobsRepository); + } + } + + public async Task AddNotificationsAsync(AddOrUpdateTaskEvent @event) + { + var course = await _coursesServiceClient.GetCourseByTask(@event.TaskId); + var task = await _coursesServiceClient.GetTask(@event.TaskId); + if (course == null) return; + + var studentIds = course.CourseMates.Select(t => t.StudentId).ToArray(); + var accountsData = await _authServiceClient.GetAccountsData(studentIds); + + var url = _configuration["Url"]; + var message = task.PublicationDate < DateTime.UtcNow + ? $"Задача {task.Title}" + + $" из курса {course.Name} обновлена." + : $"В курсе {course.Name}" + + $" опубликована новая задача {task.Title}." + + (task.DeadlineDate is { } deadline ? $"\n\nДедлайн: {deadline:U}" : ""); + + foreach (var student in accountsData) + { + var notification = new Notification + { + Sender = "CourseService", + Body = message, + Category = CategoryState.Homeworks, + Date = DateTime.UtcNow, + Owner = student.UserId + }; + + var addNotificationTask = _notificationRepository.AddAsync(notification); + var sendEmailTask = _emailService.SendEmailAsync(notification, student.Email, "Новая задача"); + + await Task.WhenAll(addNotificationTask, sendEmailTask); + } + } + } +} \ No newline at end of file diff --git a/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/DeleteTaskEventHandler.cs b/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/DeleteTaskEventHandler.cs new file mode 100644 index 000000000..db8ffa80a --- /dev/null +++ b/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/DeleteTaskEventHandler.cs @@ -0,0 +1,24 @@ +using System.Threading.Tasks; +using HwProj.EventBus.Client.Interfaces; +using HwProj.Models.Events.CourseEvents; +using HwProj.NotificationsService.API.Jobs; +using HwProj.NotificationsService.API.Repositories; + +namespace HwProj.NotificationsService.API.EventHandlers +{ + public class DeleteTaskEventHandler : EventHandlerBase + { + private readonly IScheduleJobsRepository _scheduleJobsRepository; + + public DeleteTaskEventHandler(IScheduleJobsRepository scheduleJobsRepository) + { + _scheduleJobsRepository = scheduleJobsRepository; + } + + public override async Task HandleAsync(DeleteTaskEvent @event) + { + await EventHandlerExtensions.DeleteScheduleJobsAsync(@event, @event.TaskId, + _scheduleJobsRepository); + } + } +} \ No newline at end of file diff --git a/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/InviteLecturerEventHandler.cs b/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/InviteLecturerEventHandler.cs index f8ea9fcff..fadfe6144 100644 --- a/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/InviteLecturerEventHandler.cs +++ b/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/InviteLecturerEventHandler.cs @@ -1,7 +1,7 @@ +using System; using System.Threading.Tasks; -using HwProj.AuthService.API.Events; +using HwProj.Models.Events.AuthEvents; using HwProj.EventBus.Client.Interfaces; -using HwProj.Models; using HwProj.Models.NotificationsService; using HwProj.NotificationsService.API.Repositories; using HwProj.NotificationsService.API.Services; @@ -26,7 +26,7 @@ public override async Task HandleAsync(InviteLecturerEvent @event) Sender = "AuthService", Body = "Вас добавили в список лекторов.", Category = CategoryState.Courses, - Date = DateTimeUtils.GetMoscowNow(), + Date = DateTime.UtcNow, Owner = @event.UserId }; diff --git a/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/LecturerAcceptToCourseEventHandler.cs b/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/LecturerAcceptToCourseEventHandler.cs index 6949e1854..f2e827d26 100644 --- a/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/LecturerAcceptToCourseEventHandler.cs +++ b/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/LecturerAcceptToCourseEventHandler.cs @@ -1,12 +1,12 @@ +using System; using System.Threading.Tasks; using HwProj.AuthService.Client; -using HwProj.CoursesService.API.Events; using HwProj.EventBus.Client.Interfaces; -using HwProj.Models; using HwProj.Models.NotificationsService; using HwProj.NotificationsService.API.Repositories; using HwProj.NotificationsService.API.Services; using Microsoft.Extensions.Configuration; +using HwProj.Models.Events.CourseEvents; namespace HwProj.NotificationsService.API.EventHandlers { @@ -37,7 +37,7 @@ public override async Task HandleAsync(LecturerAcceptToCourseEvent @event) Body = $"Вас приняли на курс {@event.CourseName}.", Category = CategoryState.Courses, - Date = DateTimeUtils.GetMoscowNow(), + Date = DateTime.UtcNow, Owner = @event.StudentId }; diff --git a/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/LecturerInvitedToCourseEventHandler.cs b/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/LecturerInvitedToCourseEventHandler.cs index 22d0bb7a2..0a181fe8e 100644 --- a/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/LecturerInvitedToCourseEventHandler.cs +++ b/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/LecturerInvitedToCourseEventHandler.cs @@ -1,11 +1,11 @@ +using System; using System.Threading.Tasks; -using HwProj.CoursesService.API.Events; using HwProj.EventBus.Client.Interfaces; -using HwProj.Models; using HwProj.Models.NotificationsService; using HwProj.NotificationsService.API.Repositories; using HwProj.NotificationsService.API.Services; using Microsoft.Extensions.Configuration; +using HwProj.Models.Events.CourseEvents; namespace HwProj.NotificationsService.API.EventHandlers { @@ -33,7 +33,7 @@ public override async Task HandleAsync(LecturerInvitedToCourseEvent @event) Body = $"Вас пригласили в качестве преподавателя на курс {@event.CourseName}.", Category = CategoryState.Courses, - Date = DateTimeUtils.GetMoscowNow(), + Date = DateTime.UtcNow, Owner = @event.MentorId }; diff --git a/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/LecturerRejectToCourseEventHandler.cs b/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/LecturerRejectToCourseEventHandler.cs index cd9b28ab9..f7098e474 100644 --- a/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/LecturerRejectToCourseEventHandler.cs +++ b/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/LecturerRejectToCourseEventHandler.cs @@ -1,12 +1,12 @@ +using System; using System.Threading.Tasks; using HwProj.AuthService.Client; -using HwProj.CoursesService.API.Events; using HwProj.EventBus.Client.Interfaces; -using HwProj.Models; using HwProj.Models.NotificationsService; using HwProj.NotificationsService.API.Repositories; using HwProj.NotificationsService.API.Services; using Microsoft.Extensions.Configuration; +using HwProj.Models.Events.CourseEvents; namespace HwProj.NotificationsService.API.EventHandlers { @@ -37,7 +37,7 @@ public override async Task HandleAsync(LecturerRejectToCourseEvent @event) Body = $"Вас не приняли на курс {@event.CourseName}.", Category = CategoryState.Courses, - Date = DateTimeUtils.GetMoscowNow(), + Date = DateTime.UtcNow, Owner = @event.StudentId }; diff --git a/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/NewCourseMateHandler.cs b/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/NewCourseMateHandler.cs index e9e3b1a55..ddefa9283 100644 --- a/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/NewCourseMateHandler.cs +++ b/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/NewCourseMateHandler.cs @@ -1,12 +1,12 @@ +using System; using System.Threading.Tasks; using HwProj.AuthService.Client; -using HwProj.CoursesService.API.Events; using HwProj.EventBus.Client.Interfaces; -using HwProj.Models; using HwProj.Models.NotificationsService; using HwProj.NotificationsService.API.Repositories; using HwProj.NotificationsService.API.Services; using Microsoft.Extensions.Configuration; +using HwProj.Models.Events.CourseEvents; namespace HwProj.NotificationsService.API.EventHandlers { @@ -44,7 +44,7 @@ public override async Task HandleAsync(NewCourseMateEvent @event) $"Студент {user.Name} {user.Surname}" + $" подал заявку на вступление в курс {@event.CourseName}.", Category = CategoryState.Courses, - Date = DateTimeUtils.GetMoscowNow(), + Date = DateTime.UtcNow, HasSeen = false, Owner = m }; diff --git a/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/NewHomeworkEventHandler.cs b/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/NewHomeworkEventHandler.cs index 716374aca..17351de68 100644 --- a/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/NewHomeworkEventHandler.cs +++ b/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/NewHomeworkEventHandler.cs @@ -1,13 +1,13 @@ +using System; using System.Linq; using System.Threading.Tasks; using HwProj.AuthService.Client; using HwProj.EventBus.Client.Interfaces; using HwProj.Models.NotificationsService; using HwProj.NotificationsService.API.Repositories; -using HwProj.CoursesService.API.Events; -using HwProj.Models; using HwProj.NotificationsService.API.Services; using Microsoft.Extensions.Configuration; +using HwProj.Models.Events.CourseEvents; namespace HwProj.NotificationsService.API.EventHandlers { @@ -44,9 +44,9 @@ public override async Task HandleAsync(NewHomeworkEvent @event) $"В курсе {@event.Course.Name}" + $" опубликована новая домашняя работа {@event.Homework}.", Category = CategoryState.Homeworks, - Date = DateTimeUtils.GetMoscowNow(), + Date = DateTime.UtcNow, HasSeen = false, - Owner = student!.UserId + Owner = student.UserId }; var addNotificationTask = _notificationRepository.AddAsync(notification); diff --git a/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/NewHomeworkTaskEventHandler.cs b/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/NewHomeworkTaskEventHandler.cs deleted file mode 100644 index ba832df25..000000000 --- a/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/NewHomeworkTaskEventHandler.cs +++ /dev/null @@ -1,61 +0,0 @@ -using System.Linq; -using System.Threading.Tasks; -using HwProj.AuthService.Client; -using HwProj.EventBus.Client.Interfaces; -using HwProj.Models.NotificationsService; -using HwProj.NotificationsService.API.Repositories; -using HwProj.CoursesService.API.Events; -using HwProj.Models; -using HwProj.NotificationsService.API.Services; -using Microsoft.Extensions.Configuration; - -namespace HwProj.NotificationsService.API.EventHandlers -{ - public class NewHomeworkTaskEventHandler : EventHandlerBase - { - private readonly INotificationsRepository _notificationRepository; - private readonly IAuthServiceClient _authServiceClient; - private readonly IConfigurationSection _configuration; - private readonly IEmailService _emailService; - - public NewHomeworkTaskEventHandler( - INotificationsRepository notificationRepository, - IAuthServiceClient authServiceClient, - IConfiguration configuration, - IEmailService emailService) - { - _notificationRepository = notificationRepository; - _authServiceClient = authServiceClient; - _emailService = emailService; - _configuration = configuration.GetSection("Notification"); - } - - public override async Task HandleAsync(NewHomeworkTaskEvent @event) - { - var studentIds = @event.Course.CourseMates.Select(t => t.StudentId).ToArray(); - var accountsData = await _authServiceClient.GetAccountsData(studentIds); - var url = _configuration["Url"]; - - foreach (var student in accountsData) - { - var notification = new Notification - { - Sender = "CourseService", - Body = - $"В курсе {@event.Course.Name}" + - $" опубликована новая задача {@event.TaskTitle}." + - (@event.Deadline is { } deadline ? $"\n\nДедлайн: {deadline:U}" : ""), - - Category = CategoryState.Homeworks, - Date = DateTimeUtils.GetMoscowNow(), - Owner = student!.UserId - }; - - var addNotificationTask = _notificationRepository.AddAsync(notification); - var sendEmailTask = _emailService.SendEmailAsync(notification, student.Email, "Новая задача"); - - await Task.WhenAll(addNotificationTask, sendEmailTask); - } - } - } -} diff --git a/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/PasswordRecoveryEventHandler.cs b/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/PasswordRecoveryEventHandler.cs index c77512fb1..b32c5cf93 100644 --- a/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/PasswordRecoveryEventHandler.cs +++ b/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/PasswordRecoveryEventHandler.cs @@ -1,8 +1,8 @@ -using System.Threading.Tasks; +using System; +using System.Threading.Tasks; using System.Web; -using HwProj.AuthService.API.Events; +using HwProj.Models.Events.AuthEvents; using HwProj.EventBus.Client.Interfaces; -using HwProj.Models; using HwProj.Models.NotificationsService; using HwProj.NotificationsService.API.Repositories; using HwProj.NotificationsService.API.Services; @@ -36,7 +36,7 @@ public override async Task HandleAsync(PasswordRecoveryEvent @event) $"Для изменения пароля перейдите по ссылке
Сменить пароль

" + $"Если вы не запрашивали сброс пароля, проигнорируйте это письмо.", Category = CategoryState.Profile, - Date = DateTimeUtils.GetMoscowNow(), + Date = DateTime.UtcNow, HasSeen = false, Owner = @event.UserId }; @@ -45,7 +45,7 @@ public override async Task HandleAsync(PasswordRecoveryEvent @event) Sender = "AuthService", Body = $"{@event.Name} {@event.Surname}, был запрошен сброс вашего пароля.", Category = CategoryState.Profile, - Date = DateTimeUtils.GetMoscowNow(), + Date = DateTime.UtcNow, HasSeen = false, Owner = @event.UserId }; diff --git a/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/RateEventHandler.cs b/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/RateEventHandler.cs index 55d83bcf1..638403618 100644 --- a/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/RateEventHandler.cs +++ b/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/RateEventHandler.cs @@ -1,11 +1,11 @@ +using System; using System.Threading.Tasks; using HwProj.AuthService.Client; using HwProj.EventBus.Client.Interfaces; -using HwProj.Models; using HwProj.Models.NotificationsService; using HwProj.NotificationsService.API.Repositories; using HwProj.NotificationsService.API.Services; -using HwProj.SolutionsService.API.Events; +using HwProj.Models.Events.SolutionEvents; using Microsoft.Extensions.Configuration; namespace HwProj.NotificationsService.API.EventHandlers @@ -44,7 +44,7 @@ public override async Task HandleAsync(RateEvent @event) $"{@event.Solution.Rating}/{@event.Task.MaxRating}." + $"{commentBody}", Category = CategoryState.Homeworks, - Date = DateTimeUtils.GetMoscowNow(), + Date = DateTime.UtcNow, HasSeen = false, Owner = @event.Solution.StudentId }; diff --git a/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/RegisterEventHandler.cs b/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/RegisterEventHandler.cs index e094fdc05..80bdf138e 100644 --- a/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/RegisterEventHandler.cs +++ b/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/RegisterEventHandler.cs @@ -1,7 +1,7 @@ -using System.Threading.Tasks; -using HwProj.AuthService.API.Events; +using System; +using System.Threading.Tasks; +using HwProj.Models.Events.AuthEvents; using HwProj.EventBus.Client.Interfaces; -using HwProj.Models; using HwProj.Models.NotificationsService; using HwProj.NotificationsService.API.Repositories; using HwProj.NotificationsService.API.Services; @@ -26,7 +26,7 @@ public override async Task HandleAsync(StudentRegisterEvent @event) Sender = "AuthService", Body = $"{@event.Name} {@event.Surname}, Добро Пожаловать в HwProj2.", Category = CategoryState.Profile, - Date = DateTimeUtils.GetMoscowNow(), + Date = DateTime.UtcNow, HasSeen = false, Owner = @event.UserId }; diff --git a/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/StudentPassTaskEventHandler.cs b/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/StudentPassTaskEventHandler.cs index 6af48b207..e995bcb8c 100644 --- a/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/StudentPassTaskEventHandler.cs +++ b/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/StudentPassTaskEventHandler.cs @@ -5,7 +5,7 @@ using HwProj.NotificationsService.API.Models; using HwProj.NotificationsService.API.Repositories; using HwProj.NotificationsService.API.Services; -using HwProj.SolutionsService.API.Events; +using HwProj.Models.Events.SolutionEvents; using Microsoft.Extensions.Configuration; namespace HwProj.NotificationsService.API.EventHandlers diff --git a/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/UpdateHomeworkEventHandler.cs b/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/UpdateHomeworkEventHandler.cs index d2bbc4de3..2f1496225 100644 --- a/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/UpdateHomeworkEventHandler.cs +++ b/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/UpdateHomeworkEventHandler.cs @@ -1,10 +1,10 @@ +using System; using System.Threading.Tasks; using HwProj.AuthService.Client; using HwProj.EventBus.Client.Interfaces; using HwProj.Models.NotificationsService; using HwProj.NotificationsService.API.Repositories; -using HwProj.CoursesService.API.Events; -using HwProj.Models; +using HwProj.Models.Events.CourseEvents; using HwProj.NotificationsService.API.Services; using Microsoft.Extensions.Configuration; @@ -40,7 +40,7 @@ public override async Task HandleAsync(UpdateHomeworkEvent @event) Body = $"В курсе {@event.Course.Name} домашнее задание {@event.Homework.Title} обновлено.", Category = CategoryState.Homeworks, - Date = DateTimeUtils.GetMoscowNow(), + Date = DateTime.UtcNow, HasSeen = false, Owner = student.StudentId }; diff --git a/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/UpdateTaskMaxRatingEventHandler.cs b/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/UpdateTaskMaxRatingEventHandler.cs deleted file mode 100644 index 1289a1333..000000000 --- a/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/UpdateTaskMaxRatingEventHandler.cs +++ /dev/null @@ -1,61 +0,0 @@ -using System.Threading.Tasks; -using AutoMapper; -using HwProj.AuthService.Client; -using HwProj.EventBus.Client.Interfaces; -using HwProj.Models.NotificationsService; -using HwProj.NotificationsService.API.Repositories; -using HwProj.CoursesService.API.Events; -using HwProj.Models; -using HwProj.Models.AuthService.DTO; -using HwProj.NotificationsService.API.Services; -using Microsoft.Extensions.Configuration; - -namespace HwProj.NotificationsService.API.EventHandlers -{ - public class UpdateTaskMaxRatingEventHandler : EventHandlerBase - { - private readonly INotificationsRepository _notificationRepository; - private readonly IAuthServiceClient _authServiceClient; - private readonly IMapper _mapper; - private readonly IConfigurationSection _configuration; - private readonly IEmailService _emailService; - - public UpdateTaskMaxRatingEventHandler( - INotificationsRepository notificationRepository, - IMapper mapper, - IAuthServiceClient authServiceClient, - IConfiguration configuration, - IEmailService emailService) - { - _notificationRepository = notificationRepository; - _mapper = mapper; - _authServiceClient = authServiceClient; - _emailService = emailService; - _configuration = configuration.GetSection("Notification"); - } - - public override async Task HandleAsync(UpdateTaskMaxRatingEvent @event) - { - foreach (var student in @event.Course.CourseMates) - { - var studentAccount = await _authServiceClient.GetAccountData(student.StudentId); - var studentModel = _mapper.Map(studentAccount); - var notification = new Notification - { - Sender = "CourseService", - Body = $"Задача {@event.Task.Title}" + - $" из курса {@event.Course.Name} обновлена.", - Category = CategoryState.Courses, - Date = DateTimeUtils.GetMoscowNow(), - HasSeen = false, - Owner = student.StudentId - }; - - var addNotificationTask = _notificationRepository.AddAsync(notification); - var sendEmailTask = _emailService.SendEmailAsync(notification, studentModel.Email, "Домашняя работа"); - - await Task.WhenAll(addNotificationTask, sendEmailTask); - } - } - } -} diff --git a/HwProj.NotificationsService/HwProj.NotificationsService.API/HwProj.NotificationsService.API.csproj b/HwProj.NotificationsService/HwProj.NotificationsService.API/HwProj.NotificationsService.API.csproj index 24abc2bd8..7a5b10658 100644 --- a/HwProj.NotificationsService/HwProj.NotificationsService.API/HwProj.NotificationsService.API.csproj +++ b/HwProj.NotificationsService/HwProj.NotificationsService.API/HwProj.NotificationsService.API.csproj @@ -15,6 +15,9 @@ + + + @@ -23,12 +26,10 @@ - + - - diff --git a/HwProj.NotificationsService/HwProj.NotificationsService.API/Jobs/EventHandlerExtensions.cs b/HwProj.NotificationsService/HwProj.NotificationsService.API/Jobs/EventHandlerExtensions.cs new file mode 100644 index 000000000..d17b471ab --- /dev/null +++ b/HwProj.NotificationsService/HwProj.NotificationsService.API/Jobs/EventHandlerExtensions.cs @@ -0,0 +1,50 @@ +using System; +using System.Linq.Expressions; +using System.Threading.Tasks; +using Hangfire; +using HwProj.EventBus.Client; +using HwProj.NotificationsService.API.Repositories; +using Microsoft.Azure.KeyVault.Models; + +namespace HwProj.NotificationsService.API.Jobs +{ + public static class EventHandlerExtensions where TEvent : Event + { + public static async Task AddScheduleJobAsync(TEvent @event, long itemId, DateTime publicationDate, + Expression> jobFunc, IScheduleJobsRepository jobsRepository) + { + var jobId = BackgroundJob.Schedule(jobFunc, publicationDate); + + if (jobId == null) + throw new InvalidOperationException($"Невозможно создать отложенное событие для {@event.EventName}"); + + var scheduleJob = new ScheduleJob(@event, itemId, jobId); + await jobsRepository.AddAsync(scheduleJob); + BackgroundJob.ContinueJobWith( + jobId, + () => jobsRepository.DeleteAsync(new[] { scheduleJob }), + JobContinuationOptions.OnAnyFinishedState + ); + } + + public static async Task UpdateScheduleJobAsync(TEvent @event, long itemId, DateTime publicationDate, + Expression> jobFunc, IScheduleJobsRepository jobsRepository) + { + var scheduleJob = await jobsRepository.GetAsync(@event.Category, @event.EventName, itemId); + if (scheduleJob == null) return; + + BackgroundJob.Reschedule(scheduleJob.JobId, publicationDate); + } + + public static async Task DeleteScheduleJobsAsync(TEvent @event, long itemId, + IScheduleJobsRepository jobsRepository) + { + var scheduleJobs = await jobsRepository.FindAllInCategoryAsync(@event.Category, itemId); + + foreach (var scheduleJob in scheduleJobs) + { + BackgroundJob.Delete(scheduleJob.JobId); + } + } + } +} diff --git a/HwProj.NotificationsService/HwProj.NotificationsService.API/Jobs/ScheduleJob.cs b/HwProj.NotificationsService/HwProj.NotificationsService.API/Jobs/ScheduleJob.cs new file mode 100644 index 000000000..13926fbf3 --- /dev/null +++ b/HwProj.NotificationsService/HwProj.NotificationsService.API/Jobs/ScheduleJob.cs @@ -0,0 +1,24 @@ +using HwProj.EventBus.Client; + +namespace HwProj.NotificationsService.API.Jobs +{ + public class ScheduleJob + { + public EventCategory Category { get; set; } + public string EventName { get; set; } + public long ItemId { get; set; } + public string JobId { get; set; } + + public ScheduleJob(Event @event, long itemId, string jobId) + { + Category = @event.Category; + EventName = @event.EventName; + ItemId = itemId; + JobId = jobId; + } + + public ScheduleJob() + { + } + } +} diff --git a/HwProj.NotificationsService/HwProj.NotificationsService.API/Migrations/20231023000606_NotificationSettings.Designer.cs b/HwProj.NotificationsService/HwProj.NotificationsService.API/Migrations/20231023000606_NotificationSettings.Designer.cs deleted file mode 100644 index 71e04909a..000000000 --- a/HwProj.NotificationsService/HwProj.NotificationsService.API/Migrations/20231023000606_NotificationSettings.Designer.cs +++ /dev/null @@ -1,64 +0,0 @@ -// -using System; -using HwProj.NotificationsService.API.Models; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; - -namespace HwProj.NotificationsService.API.Migrations -{ - [DbContext(typeof(NotificationsContext))] - [Migration("20231023000606_NotificationSettings")] - partial class NotificationSettings - { - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "2.2.6-servicing-10079") - .HasAnnotation("Relational:MaxIdentifierLength", 128) - .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); - - modelBuilder.Entity("HwProj.Models.NotificationsService.Notification", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); - - b.Property("Body"); - - b.Property("Category"); - - b.Property("Date"); - - b.Property("HasSeen"); - - b.Property("Owner"); - - b.Property("Sender"); - - b.HasKey("Id"); - - b.ToTable("Notifications"); - }); - - modelBuilder.Entity("HwProj.NotificationsService.API.Models.NotificationsSetting", b => - { - b.Property("UserId"); - - b.Property("Category"); - - b.Property("IsEnabled"); - - b.HasKey("UserId", "Category"); - - b.HasIndex("UserId"); - - b.ToTable("Settings"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/HwProj.NotificationsService/HwProj.NotificationsService.API/Migrations/20231023000606_NotificationSettings.cs b/HwProj.NotificationsService/HwProj.NotificationsService.API/Migrations/20231023000606_NotificationSettings.cs deleted file mode 100644 index 8970dda79..000000000 --- a/HwProj.NotificationsService/HwProj.NotificationsService.API/Migrations/20231023000606_NotificationSettings.cs +++ /dev/null @@ -1,28 +0,0 @@ -using Microsoft.EntityFrameworkCore.Migrations; - -namespace HwProj.NotificationsService.API.Migrations -{ - public partial class NotificationSettings : Migration - { - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.CreateTable( - name: "Settings", - columns: table => new - { - UserId = table.Column(nullable: false), - Category = table.Column(nullable: false), - IsEnabled = table.Column(nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_Settings", x => new { x.UserId, x.Category }); - }); - - migrationBuilder.CreateIndex( - name: "IX_Settings_UserId", - table: "Settings", - column: "UserId"); - } - } -} diff --git a/HwProj.NotificationsService/HwProj.NotificationsService.API/Migrations/NotificationsContextModelSnapshot.cs b/HwProj.NotificationsService/HwProj.NotificationsService.API/Migrations/NotificationsContextModelSnapshot.cs deleted file mode 100644 index 2e38006a5..000000000 --- a/HwProj.NotificationsService/HwProj.NotificationsService.API/Migrations/NotificationsContextModelSnapshot.cs +++ /dev/null @@ -1,62 +0,0 @@ -// -using System; -using HwProj.NotificationsService.API.Models; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; - -namespace HwProj.NotificationsService.API.Migrations -{ - [DbContext(typeof(NotificationsContext))] - partial class NotificationsContextModelSnapshot : ModelSnapshot - { - protected override void BuildModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "2.2.6-servicing-10079") - .HasAnnotation("Relational:MaxIdentifierLength", 128) - .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); - - modelBuilder.Entity("HwProj.Models.NotificationsService.Notification", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); - - b.Property("Body"); - - b.Property("Category"); - - b.Property("Date"); - - b.Property("HasSeen"); - - b.Property("Owner"); - - b.Property("Sender"); - - b.HasKey("Id"); - - b.ToTable("Notifications"); - }); - - modelBuilder.Entity("HwProj.NotificationsService.API.Models.NotificationsSetting", b => - { - b.Property("UserId"); - - b.Property("Category"); - - b.Property("IsEnabled"); - - b.HasKey("UserId", "Category"); - - b.HasIndex("UserId"); - - b.ToTable("Settings"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/HwProj.NotificationsService/HwProj.NotificationsService.API/Models/NotificationsContext.cs b/HwProj.NotificationsService/HwProj.NotificationsService.API/Models/NotificationsContext.cs index d5ae11961..bf34110d8 100644 --- a/HwProj.NotificationsService/HwProj.NotificationsService.API/Models/NotificationsContext.cs +++ b/HwProj.NotificationsService/HwProj.NotificationsService.API/Models/NotificationsContext.cs @@ -1,4 +1,5 @@ using HwProj.Models.NotificationsService; +using HwProj.NotificationsService.API.Jobs; using Microsoft.EntityFrameworkCore; namespace HwProj.NotificationsService.API.Models @@ -7,6 +8,7 @@ public sealed class NotificationsContext : DbContext { public DbSet Notifications { get; set; } public DbSet Settings { get; set; } + public DbSet ScheduleJobs { get; set; } public NotificationsContext(DbContextOptions options) : base(options) @@ -17,6 +19,7 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity().HasIndex(n => n.UserId); modelBuilder.Entity().HasKey(n => new { n.UserId, n.Category }); + modelBuilder.Entity().HasKey(s => new { s.Category, s.EventName, s.ItemId }); } } } diff --git a/HwProj.NotificationsService/HwProj.NotificationsService.API/Repositories/ScheduleJobsRepository.cs b/HwProj.NotificationsService/HwProj.NotificationsService.API/Repositories/ScheduleJobsRepository.cs new file mode 100644 index 000000000..f1cbe9e43 --- /dev/null +++ b/HwProj.NotificationsService/HwProj.NotificationsService.API/Repositories/ScheduleJobsRepository.cs @@ -0,0 +1,71 @@ +using System.Linq; +using System.Threading.Tasks; +using HwProj.EventBus.Client; +using HwProj.NotificationsService.API.Jobs; +using HwProj.NotificationsService.API.Models; +using Microsoft.EntityFrameworkCore; +using Z.EntityFramework.Plus; + +namespace HwProj.NotificationsService.API.Repositories +{ + public interface IScheduleJobsRepository + { + public Task AddAsync(ScheduleJob scheduleJob); + public Task GetAsync(EventCategory category, string eventName, long itemId); + public Task DeleteAsync(ScheduleJob[] jobs); + public Task FindAllInCategoryAsync(EventCategory category, long itemId); + } + + + public class ScheduleJobsRepository : IScheduleJobsRepository + { + private readonly NotificationsContext _context; + + public ScheduleJobsRepository(NotificationsContext context) + { + _context = context; + } + + public async Task AddAsync(ScheduleJob scheduleJob) + { + await _context.AddAsync(scheduleJob); + await _context.SaveChangesAsync(); + } + + public async Task GetAsync(EventCategory category, string eventName, long itemId) + { + return await _context.Set().FindAsync(category, eventName, itemId); + } + + public async Task DeleteAsync(Event @event, long itemId) + { + await _context.Set() + .Where(scheduleJob => + scheduleJob.Category == @event.Category && + scheduleJob.EventName == @event.EventName && + scheduleJob.ItemId == itemId) + .DeleteAsync(); + } + + public async Task DeleteAsync(ScheduleJob[] jobs) + { + _context.Set().RemoveRange(jobs); + await _context.SaveChangesAsync(); + } + + public async Task DeleteAllInCategoryByItemIdAsync(Event @event, long itemId) + { + await _context.Set() + .Where(scheduleJob => scheduleJob.Category == @event.Category && scheduleJob.ItemId == itemId) + .DeleteAsync(); + } + + public async Task FindAllInCategoryAsync(EventCategory category, long itemId) + { + return await _context.Set() + .Where(scheduleJob => scheduleJob.Category == category && scheduleJob.ItemId == itemId) + .AsNoTracking() + .ToArrayAsync(); + } + } +} diff --git a/HwProj.NotificationsService/HwProj.NotificationsService.API/Startup.cs b/HwProj.NotificationsService/HwProj.NotificationsService.API/Startup.cs index c6abaddfe..5db040209 100644 --- a/HwProj.NotificationsService/HwProj.NotificationsService.API/Startup.cs +++ b/HwProj.NotificationsService/HwProj.NotificationsService.API/Startup.cs @@ -1,19 +1,20 @@ -using HwProj.AuthService.API.Events; +using Hangfire; +using HwProj.Models.Events.AuthEvents; using HwProj.AuthService.Client; +using HwProj.CoursesService.Client; using HwProj.EventBus.Client.Interfaces; +using HwProj.Models.Events.CourseEvents; using HwProj.NotificationsService.API.EventHandlers; using HwProj.NotificationsService.API.Models; using HwProj.NotificationsService.API.Repositories; using HwProj.NotificationsService.API.Services; +using HwProj.Models.Events.SolutionEvents; using HwProj.Utils.Configuration; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; -using HwProj.CoursesService.API.Events; -using HwProj.SolutionsService.API.Events; -using UpdateTaskMaxRatingEvent = HwProj.CoursesService.API.Events.UpdateTaskMaxRatingEvent; namespace HwProj.NotificationsService.API { @@ -29,20 +30,31 @@ public Startup(IConfiguration configuration) public void ConfigureServices(IServiceCollection services) { var connectionString = ConnectionString.GetConnectionString(Configuration); + + // Add Hangfire services. + services.AddHangfire(configuration => configuration + .SetDataCompatibilityLevel(CompatibilityLevel.Version_180) + .UseSimpleAssemblyNameTypeSerializer() + .UseRecommendedSerializerSettings() + .UseSqlServerStorage(Configuration.GetConnectionString("HangfireConnection"))); + + // Add the processing server as IHostedService + services.AddHangfireServer(); services.AddDbContext(options => options.UseSqlServer(connectionString)); services.AddScoped(); services.AddScoped(); services.AddEventBus(Configuration); + services.AddTransient(); services.AddTransient, RegisterEventHandler>(); services.AddTransient, RateEventHandler>(); services.AddTransient, StudentPassTaskEventHandler>(); services.AddTransient, UpdateHomeworkEventHandler>(); - services.AddTransient, UpdateTaskMaxRatingEventHandler>(); + services.AddTransient, AddOrUpdateTaskEventHandler>(); + services.AddTransient, DeleteTaskEventHandler>(); services.AddTransient, LecturerAcceptToCourseEventHandler>(); services.AddTransient, LecturerRejectToCourseEventHandler>(); services.AddTransient, LecturerInvitedToCourseEventHandler>(); services.AddTransient, NewHomeworkEventHandler>(); - services.AddTransient, NewHomeworkTaskEventHandler>(); services.AddTransient, InviteLecturerEventHandler>(); services.AddTransient, NewCourseMateHandler>(); services.AddTransient, PasswordRecoveryEventHandler>(); @@ -50,7 +62,8 @@ public void ConfigureServices(IServiceCollection services) services.AddHttpClient(); services.AddAuthServiceClient(); - + services.AddCoursesServiceClient(); + services.ConfigureHwProjServices("Notifications API"); } @@ -63,17 +76,18 @@ public void Configure(IApplicationBuilder app, IHostingEnvironment env, IEventBu eventBustSubscriber.Subscribe(); eventBustSubscriber.Subscribe(); eventBustSubscriber.Subscribe(); - eventBustSubscriber.Subscribe(); + eventBustSubscriber.Subscribe(); + eventBustSubscriber.Subscribe(); eventBustSubscriber.Subscribe(); eventBustSubscriber.Subscribe(); eventBustSubscriber.Subscribe(); eventBustSubscriber.Subscribe(); - eventBustSubscriber.Subscribe(); eventBustSubscriber.Subscribe(); eventBustSubscriber.Subscribe(); eventBustSubscriber.Subscribe(); } - + + app.UseHangfireDashboard(); app.ConfigureHwProj(env, "Notifications API", context); } } diff --git a/HwProj.NotificationsService/HwProj.NotificationsService.API/appsettings.json b/HwProj.NotificationsService/HwProj.NotificationsService.API/appsettings.json index 6f9707df9..4a4d36366 100644 --- a/HwProj.NotificationsService/HwProj.NotificationsService.API/appsettings.json +++ b/HwProj.NotificationsService/HwProj.NotificationsService.API/appsettings.json @@ -1,11 +1,13 @@ { "ConnectionStrings": { "DefaultConnectionForWindows": "Server=(localdb)\\mssqllocaldb;Database=NotificationsServiceDB;Trusted_Connection=True;MultipleActiveResultSets=True", - "DefaultConnectionForLinux": "Server=localhost,1433;Database=NotificationsServiceDB;User ID=SA;Password=password_1234;" + "DefaultConnectionForLinux": "Server=localhost,1433;Database=NotificationsServiceDB;User ID=SA;Password=password_1234;", + "HangfireConnection": "Server=(localdb)\\mssqllocaldb;Database=HangfireDB;Trusted_Connection=True;" }, "Logging": { "LogLevel": { - "Default": "Warning" + "Default": "Warning", + "Hangfire": "Information" } }, "AllowedHosts": "*", diff --git a/HwProj.SolutionsService/HwProj.SolutionsService.API/Migrations/20231025212103_SolutionsIndex.Designer.cs b/HwProj.SolutionsService/HwProj.SolutionsService.API/Migrations/20231025212103_SolutionsIndex.Designer.cs deleted file mode 100644 index efc89b036..000000000 --- a/HwProj.SolutionsService/HwProj.SolutionsService.API/Migrations/20231025212103_SolutionsIndex.Designer.cs +++ /dev/null @@ -1,57 +0,0 @@ -// -using System; -using HwProj.SolutionsService.API.Models; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; - -namespace HwProj.SolutionsService.API.Migrations -{ - [DbContext(typeof(SolutionContext))] - [Migration("20231025212103_SolutionsIndex")] - partial class SolutionsIndex - { - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "2.2.6-servicing-10079") - .HasAnnotation("Relational:MaxIdentifierLength", 128) - .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); - - modelBuilder.Entity("HwProj.Models.SolutionsService.Solution", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); - - b.Property("Comment"); - - b.Property("GithubUrl"); - - b.Property("GroupId"); - - b.Property("LecturerComment"); - - b.Property("PublicationDate"); - - b.Property("Rating"); - - b.Property("State"); - - b.Property("StudentId"); - - b.Property("TaskId"); - - b.HasKey("Id"); - - b.HasIndex("TaskId"); - - b.ToTable("Solutions"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/HwProj.SolutionsService/HwProj.SolutionsService.API/Migrations/20231025212103_SolutionsIndex.cs b/HwProj.SolutionsService/HwProj.SolutionsService.API/Migrations/20231025212103_SolutionsIndex.cs deleted file mode 100644 index 4b3e5e7f3..000000000 --- a/HwProj.SolutionsService/HwProj.SolutionsService.API/Migrations/20231025212103_SolutionsIndex.cs +++ /dev/null @@ -1,15 +0,0 @@ -using Microsoft.EntityFrameworkCore.Migrations; - -namespace HwProj.SolutionsService.API.Migrations -{ - public partial class SolutionsIndex : Migration - { - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.CreateIndex( - name: "IX_Solutions_TaskId", - table: "Solutions", - column: "TaskId"); - } - } -} diff --git a/HwProj.SolutionsService/HwProj.SolutionsService.API/Migrations/SolutionContextModelSnapshot.cs b/HwProj.SolutionsService/HwProj.SolutionsService.API/Migrations/SolutionContextModelSnapshot.cs deleted file mode 100644 index 2111fe91c..000000000 --- a/HwProj.SolutionsService/HwProj.SolutionsService.API/Migrations/SolutionContextModelSnapshot.cs +++ /dev/null @@ -1,55 +0,0 @@ -// -using System; -using HwProj.SolutionsService.API.Models; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; - -namespace HwProj.SolutionsService.API.Migrations -{ - [DbContext(typeof(SolutionContext))] - partial class SolutionContextModelSnapshot : ModelSnapshot - { - protected override void BuildModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "2.2.6-servicing-10079") - .HasAnnotation("Relational:MaxIdentifierLength", 128) - .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); - - modelBuilder.Entity("HwProj.Models.SolutionsService.Solution", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); - - b.Property("Comment"); - - b.Property("GithubUrl"); - - b.Property("GroupId"); - - b.Property("LecturerComment"); - - b.Property("PublicationDate"); - - b.Property("Rating"); - - b.Property("State"); - - b.Property("StudentId"); - - b.Property("TaskId"); - - b.HasKey("Id"); - - b.HasIndex("TaskId"); - - b.ToTable("Solutions"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/HwProj.SolutionsService/HwProj.SolutionsService.API/Services/SolutionsService.cs b/HwProj.SolutionsService/HwProj.SolutionsService.API/Services/SolutionsService.cs index c9f7d1603..92662c645 100644 --- a/HwProj.SolutionsService/HwProj.SolutionsService.API/Services/SolutionsService.cs +++ b/HwProj.SolutionsService/HwProj.SolutionsService.API/Services/SolutionsService.cs @@ -10,7 +10,7 @@ using HwProj.Models.CoursesService.ViewModels; using HwProj.Models.SolutionsService; using HwProj.Models.StatisticsService; -using HwProj.SolutionsService.API.Events; +using HwProj.Models.Events.SolutionEvents; using HwProj.SolutionsService.API.Repositories; using Microsoft.EntityFrameworkCore;