From c749b184a9ec596419b9cdae520ed39d7ed4a6c0 Mon Sep 17 00:00:00 2001 From: Owczarek Kamil Date: Mon, 24 Jun 2024 00:30:49 +0200 Subject: [PATCH] Atached recomendation algorithm to controllers --- .../ReasnAPI/Controllers/MeController.cs | 76 +++++++++++-------- .../ReasnAPI/Controllers/UsersController.cs | 12 --- .../ReasnAPI/ReasnAPI/Mappers/EventMapper.cs | 12 +++ .../ReasnAPI/Models/API/EventSugestion.cs | 12 +++ .../Models/API/RecomendationPageRequest.cs | 8 ++ .../Models/API/RecomendationPageResponse.cs | 9 +++ .../ReasnAPI/Services/RecomendationService.cs | 34 ++++----- 7 files changed, 103 insertions(+), 60 deletions(-) create mode 100644 Server/ReasnAPI/ReasnAPI/Models/API/EventSugestion.cs create mode 100644 Server/ReasnAPI/ReasnAPI/Models/API/RecomendationPageRequest.cs create mode 100644 Server/ReasnAPI/ReasnAPI/Models/API/RecomendationPageResponse.cs diff --git a/Server/ReasnAPI/ReasnAPI/Controllers/MeController.cs b/Server/ReasnAPI/ReasnAPI/Controllers/MeController.cs index 9bd2eaa..8315293 100644 --- a/Server/ReasnAPI/ReasnAPI/Controllers/MeController.cs +++ b/Server/ReasnAPI/ReasnAPI/Controllers/MeController.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.Tracing; using FluentValidation; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; @@ -12,19 +13,14 @@ namespace ReasnAPI.Controllers; [ApiController] [Authorize] [Route("[controller]")] -public class MeController(UserService userService, EventService eventService, ParticipantService participantService, ImageService imageService) : ControllerBase +public class MeController(UserService userService, EventService eventService, ParticipantService participantService, ImageService imageService, RecomendationService recomendationService) : ControllerBase { - private readonly UserService _userService = userService; - private readonly EventService _eventService = eventService; - private readonly ParticipantService _participantService = participantService; - private readonly ImageService _imageService = imageService; - [HttpGet] [ProducesResponseType(StatusCodes.Status200OK)] public IActionResult GetCurrentUser() { - var username = _userService.GetCurrentUser().Username; - var user = _userService.GetUserByUsername(username); + var username = userService.GetCurrentUser().Username; + var user = userService.GetUserByUsername(username); return Ok(user); } @@ -37,7 +33,7 @@ public IActionResult UpdateCurrentUser( { validator.ValidateAndThrow(userDto); - var user = _userService.GetCurrentUser(); + var user = userService.GetCurrentUser(); // Users cant change their role in this endpoint if (user.Role != userDto.Role) @@ -45,7 +41,7 @@ public IActionResult UpdateCurrentUser( return Forbid(); } - var updatedUser = _userService.UpdateUser(user.Username, userDto); + var updatedUser = userService.UpdateUser(user.Username, userDto); return Ok(updatedUser); } @@ -55,8 +51,8 @@ public IActionResult UpdateCurrentUser( [ProducesResponseType(StatusCodes.Status200OK)] public IActionResult GetCurrentUserImage() { - var user = _userService.GetCurrentUser(); - var image = _imageService.GetImageByUserId(user.Id); + var user = userService.GetCurrentUser(); + var image = imageService.GetImageByUserId(user.Id); if (image is null) { @@ -71,7 +67,7 @@ public IActionResult GetCurrentUserImage() [ProducesResponseType(StatusCodes.Status201Created)] public async Task AddCurrentUserImage([FromForm] List images) { - var userId = _userService.GetCurrentUser().Id; + var userId = userService.GetCurrentUser().Id; foreach (var image in images.Where(image => image.Length > 0)) { @@ -86,7 +82,7 @@ public async Task AddCurrentUserImage([FromForm] List ImageData = fileBytes }; - _imageService.CreateImages([imageDto]); + imageService.CreateImages([imageDto]); } return Ok(); @@ -97,7 +93,7 @@ public async Task AddCurrentUserImage([FromForm] List [ProducesResponseType(StatusCodes.Status200OK)] public async Task UpdateCurrentUserImage([FromForm] List images) { - var userId = _userService.GetCurrentUser().Id; + var userId = userService.GetCurrentUser().Id; foreach (var image in images.Where(image => image.Length > 0)) { @@ -112,7 +108,7 @@ public async Task UpdateCurrentUserImage([FromForm] List UpdateCurrentUserImage([FromForm] List>(StatusCodes.Status200OK)] public IActionResult GetCurrentUserEvents() { - var user = _userService.GetCurrentUser(); - var events = _eventService.GetUserEvents(user.Username); + var user = userService.GetCurrentUser(); + var events = eventService.GetUserEvents(user.Username); if (user.Role == UserRole.Organizer) { - var organizerEvents = _eventService.GetEventsByFilter(e => e.OrganizerId == user.Id); + var organizerEvents = eventService.GetEventsByFilter(e => e.OrganizerId == user.Id); events = events.Concat(organizerEvents); } @@ -151,9 +147,9 @@ public IActionResult GetCurrentUserEvents() [ProducesResponseType(StatusCodes.Status201Created)] public IActionResult EnrollCurrentUserInEvent([FromRoute] string slug) { - var user = _userService.GetCurrentUser(); + var user = userService.GetCurrentUser(); - var participant = _participantService.CreateOrUpdateParticipant(new ParticipantDto { EventSlug = slug, Username = user.Username, Status = ParticipantStatus.Interested }); + var participant = participantService.CreateOrUpdateParticipant(new ParticipantDto { EventSlug = slug, Username = user.Username, Status = ParticipantStatus.Interested }); var location = Url.Action( action: nameof(GetCurrentUserEvents), @@ -167,8 +163,8 @@ public IActionResult EnrollCurrentUserInEvent([FromRoute] string slug) [ProducesResponseType(StatusCodes.Status200OK)] public IActionResult ConfirmCurrentUserEventAttendance([FromRoute] string slug) { - var user = _userService.GetCurrentUser(); - var participant = _participantService.CreateOrUpdateParticipant(new ParticipantDto { EventSlug = slug, Username = user.Username, Status = ParticipantStatus.Participating }); + var user = userService.GetCurrentUser(); + var participant = participantService.CreateOrUpdateParticipant(new ParticipantDto { EventSlug = slug, Username = user.Username, Status = ParticipantStatus.Participating }); return Ok(participant); } @@ -178,16 +174,36 @@ public IActionResult ConfirmCurrentUserEventAttendance([FromRoute] string slug) [ProducesResponseType(StatusCodes.Status204NoContent)] public IActionResult CancelCurrentUserEventAttendance([FromRoute] string slug) { - var userId = _userService.GetCurrentUser().Id; - _participantService.DeleteParticipant(userId, slug); + var userId = userService.GetCurrentUser().Id; + participantService.DeleteParticipant(userId, slug); return NoContent(); } [HttpGet] [Route("events/recommendations")] - public IActionResult GetCurrentUserEventRecommendations() - { - throw new NotImplementedException(); + [ProducesResponseType>(StatusCodes.Status200OK)] + public async Task GetCurrentUserEventRecommendations( + [FromQuery] int offset = 0, + [FromQuery] int limit = 10) + { + + var currentUser = userService.GetCurrentUser(); + var username = currentUser.Username; + var currentUserInterest = userService.GetUserByUsername(username).Interests; + if (currentUserInterest == null || currentUserInterest.Count == 0) + { + return Ok(new List()); + } + + var request = new RecomendationPageRequest + { + Limit = limit, + Offset = offset + }; + + var events = await recomendationService.GetEventsByInterest(currentUserInterest, username, request); + + return Ok(events); } } \ No newline at end of file diff --git a/Server/ReasnAPI/ReasnAPI/Controllers/UsersController.cs b/Server/ReasnAPI/ReasnAPI/Controllers/UsersController.cs index 23b0d23..2d3cedd 100644 --- a/Server/ReasnAPI/ReasnAPI/Controllers/UsersController.cs +++ b/Server/ReasnAPI/ReasnAPI/Controllers/UsersController.cs @@ -42,18 +42,6 @@ public IActionResult GetUserByUsername([FromRoute] string username) return Ok(user); } - [HttpGet] - [Route("{username}/recomendetevents")] - public async Task GetRecomendetEvents(string username) - { - var currentUser = _userService.GetUserByUsername(username); - var interests = currentUser.Interests; - - var events = await _recomendationService.GetEventsByInterest(interests, username); - - return Ok(events); - } - [HttpPut] [Authorize] [Route("{username}")] diff --git a/Server/ReasnAPI/ReasnAPI/Mappers/EventMapper.cs b/Server/ReasnAPI/ReasnAPI/Mappers/EventMapper.cs index 2fe04db..4385991 100644 --- a/Server/ReasnAPI/ReasnAPI/Mappers/EventMapper.cs +++ b/Server/ReasnAPI/ReasnAPI/Mappers/EventMapper.cs @@ -100,5 +100,17 @@ public static EventDto ToDto(this EventCreateRequest eventCreateRequest, int org }; } + public static EventSugestion ToSugestion(this EventDto eventDto, Participants participants, List images) + { + return new EventSugestion() + { + Name = eventDto.Name, + Slug = eventDto.Slug, + Description = eventDto.Description, + Participants = participants, + Images = images + }; + } + } } diff --git a/Server/ReasnAPI/ReasnAPI/Models/API/EventSugestion.cs b/Server/ReasnAPI/ReasnAPI/Models/API/EventSugestion.cs new file mode 100644 index 0000000..cf0cb01 --- /dev/null +++ b/Server/ReasnAPI/ReasnAPI/Models/API/EventSugestion.cs @@ -0,0 +1,12 @@ +namespace ReasnAPI.Models.API +{ + public class EventSugestion + { + public string Name { get; set; } = null!; + public string Slug { get; set; } = null!; + public string Description { get; set; } = null!; + public List? Images { get; set; } + public Participants? Participants { get; set; } + + } +} diff --git a/Server/ReasnAPI/ReasnAPI/Models/API/RecomendationPageRequest.cs b/Server/ReasnAPI/ReasnAPI/Models/API/RecomendationPageRequest.cs new file mode 100644 index 0000000..e6deaaa --- /dev/null +++ b/Server/ReasnAPI/ReasnAPI/Models/API/RecomendationPageRequest.cs @@ -0,0 +1,8 @@ +namespace ReasnAPI.Models.API +{ + public class RecomendationPageRequest + { + public int Offset { get; set; } + public int Limit { get; set; } + } +} diff --git a/Server/ReasnAPI/ReasnAPI/Models/API/RecomendationPageResponse.cs b/Server/ReasnAPI/ReasnAPI/Models/API/RecomendationPageResponse.cs new file mode 100644 index 0000000..013071d --- /dev/null +++ b/Server/ReasnAPI/ReasnAPI/Models/API/RecomendationPageResponse.cs @@ -0,0 +1,9 @@ +namespace ReasnAPI.Models.API +{ + public class RecomendationPageResponse + { + public List? Items { get; set; } + public int Offset { get; set; } + public int Limit { get; set; } + } +} diff --git a/Server/ReasnAPI/ReasnAPI/Services/RecomendationService.cs b/Server/ReasnAPI/ReasnAPI/Services/RecomendationService.cs index 962def7..db3fe98 100644 --- a/Server/ReasnAPI/ReasnAPI/Services/RecomendationService.cs +++ b/Server/ReasnAPI/ReasnAPI/Services/RecomendationService.cs @@ -10,14 +10,16 @@ using ReasnAPI.Mappers; using ReasnAPI.Models.Recomendation; using Npgsql; +using ReasnAPI.Models.API; +using ReasnAPI.Models.Enums; namespace ReasnAPI.Services { - public class RecomendationService(ReasnContext context,EventService eventService, IConfiguration configuration) + public class RecomendationService(ReasnContext context,EventService eventService, ImageService imageService, IConfiguration configuration) { private readonly string? _connectionString = configuration.GetConnectionString("DefaultValue"); - public async Task> GetEventsByInterest(List interestsDto, string username) + public async Task> GetEventsByInterest(List interestsDto, string username, RecomendationPageRequest pageRequest) { var interests = interestsDto.Select(i => i.Interest.Name).ToList(); var interestsLevels = interestsDto.Select(i => i.Level).ToList(); @@ -50,7 +52,7 @@ public async Task> GetEventsByInterest(List inte var events = await context.Events .Include(e => e.Tags) .Include(e => e.Parameters) - .Where(e => e.Tags.Any(t => tagNames.Contains(t.Name)) && !userEventSlugs.Contains(e.Slug)) + .Where(e => !userEventSlugs.Contains(e.Slug) && (e.Status == EventStatus.Approved || e.Status == EventStatus.Ongoing)) .Select(e => new { Event = e, @@ -59,27 +61,23 @@ public async Task> GetEventsByInterest(List inte }) .OrderByDescending(e => e.TotalTagValue) .Select(e => e.Event) + .Skip((pageRequest.Offset)) + .Take(pageRequest.Limit) .ToListAsync(); - var eventDtos = events.Select(e => e.ToDto()).ToList(); - - if (eventDtos.Count < 10) + + var eventSugestions = new List(); + foreach (var eventDto in eventDtos) { - int additionalEventsNeeded = 10 - eventDtos.Count; - var randomEvents = await context.Events - .Include(e => e.Tags) - .Include(e => e.Parameters) - .Where(e => !events.Contains(e)) - .OrderBy(r => r.StartAt) - .Take(additionalEventsNeeded) - .ToListAsync(); - - eventDtos.AddRange(randomEvents.Select(e => e.ToDto())); - + var participating = eventService.GetEventParticipantsCountBySlugAndStatus(eventDto.Slug, ParticipantStatus.Participating); + var interested = eventService.GetEventParticipantsCountBySlugAndStatus(eventDto.Slug, ParticipantStatus.Interested); + var participants = new Participants(participating, interested); + var images = eventService.GetEventImages(eventDto.Slug); + eventSugestions.Add(eventDto.ToSugestion(participants, images)); } - return eventDtos; + return eventSugestions; } catch (Exception ex) {