From efb71b24d35f313b26d3d5353ac528ff6b081193 Mon Sep 17 00:00:00 2001 From: eee4 <41441600+eee4@users.noreply.github.com> Date: Sun, 1 Jun 2025 20:33:58 +0200 Subject: [PATCH] fix: offload building DTOs to GUHF DTO building allows for fully returning correct event's skills and registrations --- WebApp/DTOs/EventDetailsDto.cs | 27 ++++--- WebApp/DTOs/EventRegistrationDto.cs | 15 ++++ WebApp/DTOs/EventSummaryDto.cs | 26 ++++--- WebApp/DTOs/EventSummaryNoErDto.cs | 3 +- WebApp/DTOs/SkillSummaryDto.cs | 14 ++-- WebApp/Endpoints/EventsEndpoints.cs | 30 +++++--- WebApp/Endpoints/GeneralUseHelperFunctions.cs | 48 +++++++++++- WebApp/Mapping/EventMapping.cs | 73 +++++++++++++------ WebApp/Mapping/EventSkillMapping.cs | 8 ++ WebApp/Mapping/SkillMapping.cs | 10 +-- 10 files changed, 182 insertions(+), 72 deletions(-) create mode 100644 WebApp/DTOs/EventRegistrationDto.cs diff --git a/WebApp/DTOs/EventDetailsDto.cs b/WebApp/DTOs/EventDetailsDto.cs index 9057068..1ea780d 100644 --- a/WebApp/DTOs/EventDetailsDto.cs +++ b/WebApp/DTOs/EventDetailsDto.cs @@ -1,18 +1,21 @@ -using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations; using WebApp.Entities; namespace WebApp.DTOs; // Output values in JSON file public record class EventDetailsDto -( - int EventId, - [Required] int? OrganisationId, - [Required] string? OrganisationName, - [Required][StringLength(50)] string Title, - [StringLength(500)] string Description, - [Required][StringLength(100)] string Location, - [Required] DateTime? EventDate, - ICollection EventSkills, - ICollection EventRegistrations -); +{ + public int EventId { get; set; } + [Required] public int? OrganisationId { get; set; } + [Required] public string? OrganisationName { get; set; } + [Required][StringLength(50)] public string Title { get; set; } + [StringLength(500)] public string Description { get; set; } + [Required][StringLength(100)] public string Location { get; set; } + [Required] public DateTime? EventDate { get; set; } + //ICollection EventSkills, + public ICollection EventSkills { get; set; } + public ICollection EventRegistrations { get; set; } + + public EventDetailsDto() { } +}; diff --git a/WebApp/DTOs/EventRegistrationDto.cs b/WebApp/DTOs/EventRegistrationDto.cs new file mode 100644 index 0000000..d000342 --- /dev/null +++ b/WebApp/DTOs/EventRegistrationDto.cs @@ -0,0 +1,15 @@ +using System.ComponentModel.DataAnnotations; +using WebApp.Entities; + +namespace WebApp.DTOs; + +public record class EventRegistrationDto +{ + public int EventId { get; set; } + public int UserId { get; set; } + public string UserName { get; set; } + public DateTime RegisteredAt { get; set; } + + public EventRegistrationDto() { } + +}; diff --git a/WebApp/DTOs/EventSummaryDto.cs b/WebApp/DTOs/EventSummaryDto.cs index 5835f40..9c56ab3 100644 --- a/WebApp/DTOs/EventSummaryDto.cs +++ b/WebApp/DTOs/EventSummaryDto.cs @@ -1,17 +1,19 @@ -using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations; using WebApp.Entities; namespace WebApp.DTOs; // Output values in JSON file -public record class EventSummaryDto( - int EventId, - [Required] string Organisation, - [Required] int OrganisationId, - [Required] [StringLength(50)] string Title, - [StringLength(500)] string Description, - [Required] [StringLength(100)] string Location, - [Required] DateTime? EventDate, - ICollection EventSkills, - ICollection EventRegistrations - ); +public record class EventSummaryDto { + public int EventId { get; set; } + [Required] public string Organisation { get; set; } + [Required] public int OrganisationId { get; set; } + [Required] [StringLength(50)] public string Title { get; set; } + [StringLength(500)] public string Description { get; set; } + [Required] [StringLength(100)] public string Location { get; set; } + [Required] public DateTime? EventDate { get; set; } + public ICollection EventSkills { get; set; } + public ICollection EventRegistrations { get; set; } + + +}; diff --git a/WebApp/DTOs/EventSummaryNoErDto.cs b/WebApp/DTOs/EventSummaryNoErDto.cs index 121b276..74b171d 100644 --- a/WebApp/DTOs/EventSummaryNoErDto.cs +++ b/WebApp/DTOs/EventSummaryNoErDto.cs @@ -1,4 +1,4 @@ -using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations; using WebApp.Entities; namespace WebApp.DTOs; @@ -13,4 +13,5 @@ public record class EventSummaryNoErDto( [Required][StringLength(100)] string Location, [Required] DateTime? EventDate, ICollection EventSkills + // ICollection EventSkills ); diff --git a/WebApp/DTOs/SkillSummaryDto.cs b/WebApp/DTOs/SkillSummaryDto.cs index 597d39b..c183446 100644 --- a/WebApp/DTOs/SkillSummaryDto.cs +++ b/WebApp/DTOs/SkillSummaryDto.cs @@ -1,9 +1,13 @@ -using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations; +using WebApp.Entities; namespace WebApp.DTOs; public record class SkillSummaryDto -( - [Required] int SkillId, - [Required] string SkillName -); +{ + public int? SkillId { get; set; } + public string? SkillName { get; set; } + + public SkillSummaryDto() { } + +}; diff --git a/WebApp/Endpoints/EventsEndpoints.cs b/WebApp/Endpoints/EventsEndpoints.cs index cd099ff..57f8c1f 100644 --- a/WebApp/Endpoints/EventsEndpoints.cs +++ b/WebApp/Endpoints/EventsEndpoints.cs @@ -1,5 +1,7 @@ using Microsoft.AspNetCore.Http; using Microsoft.EntityFrameworkCore; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.Intrinsics.Arm; using WebApp.Data; using WebApp.DTOs; using WebApp.Entities; @@ -40,14 +42,17 @@ namespace WebApp.Endpoints .AsNoTracking() .ToListAsync(); }); - + // GET /events/1 - group.MapGet("/{id}", + group.MapGet("/{id}", async (int id, ApplicationDbContext dbContext, HttpContext httpContext, GeneralUseHelpers guhf) => { - Event? Eve = await dbContext.Events.FindAsync(id); + Event? Eve = await dbContext + .Events + .Include(e => e.Organisation) + .FirstOrDefaultAsync(e => e.EventId == id); if (Eve is null) return Results.NotFound(); // Sprawdź, czy token należy do organizacji, a jeżeli tak, to do której. @@ -55,16 +60,14 @@ namespace WebApp.Endpoints Organisation? org = await guhf.GetOrganisationFromToken(token); // Jeśli token należy do organizacji, która utworzyła to wydarzenie, - // to zwróć także EventRegistrations. W przeciwnym razie usuń to pole - // przed jego wysłaniem! - if (org is null || org.OrganisationId != Eve.OrganisationId) Eve.EventRegistrations = []; + // to zwróć także EventRegistrations. W przeciwnym razie niech będzie to + // puste pole. + List result = await guhf.BuildDetailedEventsDto( + dbContext, + (org is not null && Eve.Organisation == org) + ); - // DLACZEGO? - Eve.Organisation = await guhf.GetOrganisationFromId(Eve.OrganisationId); - - EventDetailsDto EveDto = Eve.ToEventDetailsDto(); - - return Results.Ok(EveDto); //EventDetailsDto + return Results.Ok(result.FirstOrDefault(e => e.EventId == id)); }) .WithName(GetEventEndpointName); @@ -214,6 +217,9 @@ namespace WebApp.Endpoints // UWAGA! TO NIE POWINNO TAK DZIAŁAĆ! // KTOKOLWIEK WIDZIAŁ, KTOKOLWIEK WIE CZEMU Organisation JEST null? + // + // Odpowiedź: Bo pobieramy dane bez .Include(e => e.Organisation), + // co zapobiega masie innych problemów, m.in. rekurencyjnym importom. e.Organisation = await guhf.GetOrganisationFromId(e.OrganisationId); if (matchFound) SearchResults.Add(e.ToEventSummaryDto()); diff --git a/WebApp/Endpoints/GeneralUseHelperFunctions.cs b/WebApp/Endpoints/GeneralUseHelperFunctions.cs index 6a12bfb..7f0a2bf 100644 --- a/WebApp/Endpoints/GeneralUseHelperFunctions.cs +++ b/WebApp/Endpoints/GeneralUseHelperFunctions.cs @@ -1,5 +1,6 @@ -using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore; using WebApp.Data; +using WebApp.DTOs; using WebApp.Entities; namespace WebApp.Endpoints; @@ -112,4 +113,49 @@ public class GeneralUseHelpers // Sprawdza, czy któreś ze słów pasuje (nawet częściowo) do searchTerm return words.Any(word => word.Contains(searchTerm, StringComparison.OrdinalIgnoreCase)); } + + public async Task> BuildDetailedEventsDto(ApplicationDbContext context, bool includeEventRegistrations = false) + { + // https://khalidabuhakmeh.com/ef-core-and-aspnet-core-cycle-issue-and-solution + + // Jeśli token należy do organizacji, która utworzyła to wydarzenie, + // to zwróć także EventRegistrations. W przeciwnym razie niech będzie to + // puste pole. + ICollection ERs = new List(); + if (includeEventRegistrations) + { + ERs = await context + .EventRegistrations + .Select(er => new EventRegistrationDto + { + EventId = er.EventId, + UserId = er.UserId, + UserName = er.User.FirstName + " " + er.User.LastName, + RegisteredAt = er.RegisteredAt + }).ToListAsync(); + } + + List result = await context + .Events + .Select(e => new EventDetailsDto + { + EventId = e.EventId, + OrganisationId = e.OrganisationId, + OrganisationName = e.Organisation.Name, + Title = e.Title, + Description = e.Description, + Location = e.Location, + EventDate = e.EventDate, + EventSkills = e + .EventSkills + .Select(es => new SkillSummaryDto + { + SkillId = es.SkillId, + SkillName = es.Skill.Name + }).ToList(), + EventRegistrations = ERs + }).ToListAsync(); + + return result; + } } diff --git a/WebApp/Mapping/EventMapping.cs b/WebApp/Mapping/EventMapping.cs index df9bb2d..52305a3 100644 --- a/WebApp/Mapping/EventMapping.cs +++ b/WebApp/Mapping/EventMapping.cs @@ -1,4 +1,4 @@ -using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore; using WebApp.DTOs; using WebApp.Entities; @@ -34,20 +34,21 @@ public static class EventMapping public static EventSummaryDto ToEventSummaryDto(this Event myEvent) { - return new EventSummaryDto( - myEvent.EventId, - myEvent.Organisation!.Name, - myEvent.OrganisationId, - myEvent.Title, - myEvent.Description, - myEvent.Location, - myEvent.EventDate, - myEvent.EventSkills, - myEvent.EventRegistrations - ); + return new EventSummaryDto { + EventId = myEvent.EventId, + Organisation = myEvent.Organisation!.Name, + OrganisationId = myEvent.OrganisationId, + Title = myEvent.Title, + Description = myEvent.Description, + Location = myEvent.Location, + EventDate = myEvent.EventDate, + EventSkills = myEvent.EventSkills, + EventRegistrations = myEvent.EventRegistrations + }; } public static EventSummaryNoErDto ToEventSummaryNoErDto(this Event myEvent) { + return new EventSummaryNoErDto( myEvent.EventId, myEvent.Organisation!.Name, @@ -60,18 +61,42 @@ public static class EventMapping ); } + public static EventRegistrationDto ToEventRegistrationDto(this EventRegistration myER) + { + + return new EventRegistrationDto { + EventId = myER.EventId, + UserId = myER.UserId, + UserName = myER.User.FirstName + " " + myER.User.LastName, + RegisteredAt = myER.RegisteredAt + }; + } + public static EventDetailsDto ToEventDetailsDto(this Event myEvent) { - return new EventDetailsDto( - myEvent.EventId, - myEvent.OrganisationId, - myEvent.Organisation.Name, - myEvent.Title, - myEvent.Description, - myEvent.Location, - myEvent.EventDate, - myEvent.EventSkills, - myEvent.EventRegistrations - ); + List ssdto = new List(); + List erdto = new List(); + + foreach (EventSkill es in myEvent.EventSkills) + { + ssdto.Add(es.ToSkillSummaryDto()); + } + + foreach (EventRegistration er in myEvent.EventRegistrations) + { + erdto.Add(er.ToEventRegistrationDto()); + } + + return new EventDetailsDto { + EventId = myEvent.EventId, + OrganisationId = myEvent.OrganisationId, + OrganisationName = myEvent.Organisation.Name, + Title = myEvent.Title, + Description = myEvent.Description, + Location = myEvent.Location, + EventDate = myEvent.EventDate, + EventSkills = ssdto, + EventRegistrations = erdto + }; } -} \ No newline at end of file +} diff --git a/WebApp/Mapping/EventSkillMapping.cs b/WebApp/Mapping/EventSkillMapping.cs index 2dc0e2f..47f528f 100644 --- a/WebApp/Mapping/EventSkillMapping.cs +++ b/WebApp/Mapping/EventSkillMapping.cs @@ -13,4 +13,12 @@ public static class EventSkillMapping SkillId = SSDto.Skill, }; } + + public static SkillSummaryDto ToSkillSummaryDto(this EventSkill es) + { + return new SkillSummaryDto{ + SkillId = es.SkillId, + SkillName = es.Skill.Name + }; + } } diff --git a/WebApp/Mapping/SkillMapping.cs b/WebApp/Mapping/SkillMapping.cs index fb96056..d2889bf 100644 --- a/WebApp/Mapping/SkillMapping.cs +++ b/WebApp/Mapping/SkillMapping.cs @@ -1,4 +1,4 @@ -using WebApp.DTOs; +using WebApp.DTOs; using WebApp.Entities; namespace WebApp.Mapping @@ -16,10 +16,10 @@ namespace WebApp.Mapping public static SkillSummaryDto ToSkillSummaryDto(this Skill s) { - return new SkillSummaryDto( - s.SkillId, - s.Name - ); + return new SkillSummaryDto { + SkillId = s.SkillId, + SkillName = s.Name + }; } } }