diff --git a/WebApp/DTOs/EventRegistrationDto.cs b/WebApp/DTOs/EventRegistrationDto.cs index d000342..88918ae 100644 --- a/WebApp/DTOs/EventRegistrationDto.cs +++ b/WebApp/DTOs/EventRegistrationDto.cs @@ -1,4 +1,4 @@ -using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations; using WebApp.Entities; namespace WebApp.DTOs; diff --git a/WebApp/Endpoints/AuthEndpoints.cs b/WebApp/Endpoints/AuthEndpoints.cs index 6e019ad..7f31c3b 100644 --- a/WebApp/Endpoints/AuthEndpoints.cs +++ b/WebApp/Endpoints/AuthEndpoints.cs @@ -99,9 +99,16 @@ namespace WebApp.Endpoints if(!user.IsOrganisation) { - var events = await context.EventRegistrations + + var eventIds = await context.EventRegistrations .Where(er => er.UserId == user.UserId) - .Select(er => er.Event.ToEventSummaryNoErDto()) + .Select(er => er.EventId) + .ToListAsync(); + + var events = await context.Events + .Where(e => eventIds.Contains(e.EventId)) + .Include(e => e.Organisation) + .Select(e => e.ToEventSummaryDto()) .ToListAsync(); return Results.Ok(events); diff --git a/WebApp/Endpoints/EventRegistrationEndpoints.cs b/WebApp/Endpoints/EventRegistrationEndpoints.cs new file mode 100644 index 0000000..bb45476 --- /dev/null +++ b/WebApp/Endpoints/EventRegistrationEndpoints.cs @@ -0,0 +1,135 @@ +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http.HttpResults; +using Microsoft.EntityFrameworkCore; +using System.Security.Cryptography; +using WebApp.Data; +using WebApp.DTOs; +using WebApp.Entities; +using WebApp.Mapping; + +namespace WebApp.Endpoints +{ + public static class EventsRegistrationEndpoints + { + const string GetEventEndpointRegistrationName = "GetEventRegistration"; + + public static RouteGroupBuilder MapEventsRegistrationEndpoints(this WebApplication app) + { + var group = app.MapGroup("api/events") + .WithParameterValidation(); + + // POST /api/events/join/{id} + group.MapPost("/join/{id}", + async (int id, ApplicationDbContext dbContext, HttpContext httpContext, GeneralUseHelpers guhf) => + { + Event? Eve = await dbContext.Events.FindAsync(id); + if (Eve is null) + return Results.Json(new { success = false, error_msg = "Event not found." }); + + Token? token = await guhf.GetTokenFromHTTPContext(httpContext); + User? user = await guhf.GetUserFromToken(token); + + if (user is null || user.IsOrganisation) + return Results.Json(new { success = false, error_msg = "Unauthorized or organisations cannot register for events." }); + + if (await dbContext.EventRegistrations.AnyAsync(er => er.UserId == user.UserId && er.EventId == id)) + return Results.Json(new { success = false, error_msg = "You are already registered for this event." }); + + if (Eve.EventDate < DateTime.UtcNow) + return Results.Json(new { success = false, error_msg = "This event has already ended." }); + + EventRegistration registration = new EventRegistration + { + UserId = user.UserId, + EventId = id, + RegisteredAt = DateTime.UtcNow + }; + dbContext.EventRegistrations.Add(registration); + await dbContext.SaveChangesAsync(); + + return Results.Json(new { success = true }); + }); + + // POST /api/events/leave/{id} + group.MapPost("/leave/{id}", + async (int id, ApplicationDbContext dbContext, HttpContext httpContext, GeneralUseHelpers guhf) => + { + Event? Eve = await dbContext.Events.FindAsync(id); + if (Eve is null) + return Results.Json(new { success = false, error_msg = "Event not found." }); + + Token? token = await guhf.GetTokenFromHTTPContext(httpContext); + User? user = await guhf.GetUserFromToken(token); + + if (user is null) + return Results.Json(new { success = false, error_msg = "Unauthorized." }); + + if (!await dbContext.EventRegistrations.AnyAsync(er => er.UserId == user.UserId && er.EventId == id)) + return Results.Json(new { success = false, error_msg = "You are not registered for this event." }); + + if (Eve.EventDate < DateTime.UtcNow) + return Results.Json(new { success = false, error_msg = "This event has already ended." }); + + EventRegistration? registration = await dbContext.EventRegistrations + .FirstOrDefaultAsync(er => er.UserId == user.UserId && er.EventId == id); + + dbContext.EventRegistrations.Remove(registration); + await dbContext.SaveChangesAsync(); + + return Results.Json(new { success = true }); + }); + + // GET /api/events/registrations/{id} + group.MapGet("/registrations/{id}", + async (int id, ApplicationDbContext dbContext, HttpContext httpContext, GeneralUseHelpers guhf) => + { + Event? Eve = await dbContext.Events.FindAsync(id); + if (Eve is null) + return Results.Json(new { success = false, error_msg = "Event not found." }); + + Token? token = await guhf.GetTokenFromHTTPContext(httpContext); + Organisation? org = await guhf.GetOrganisationFromToken(token); + if (org is null || org.OrganisationId != Eve.OrganisationId) + return Results.Json(new { success = false, error_msg = "Unauthorized." }); + + var registrations = await dbContext.EventRegistrations + .Where(er => er.EventId == id) + .Select(er => er.ToEventRegistrationDto()) + .ToListAsync(); + + return Results.Json(new + { + success = true, + registrations + }); + }); + + // POST /api/events/remove/{id}/{userId} + group.MapPost("/remove/{id}/{userId}", + async (int id, int userId, ApplicationDbContext dbContext, HttpContext httpContext, GeneralUseHelpers guhf) => + { + Event? Eve = await dbContext.Events.FindAsync(id); + if (Eve is null) + return Results.Json(new { success = false, error_msg = "Event not found." }); + + Token? token = await guhf.GetTokenFromHTTPContext(httpContext); + Organisation? org = await guhf.GetOrganisationFromToken(token); + if (org is null || org.OrganisationId != Eve.OrganisationId) + return Results.Json(new { success = false, error_msg = "Unauthorized." }); + + EventRegistration? registration = await dbContext.EventRegistrations + .FirstOrDefaultAsync(er => er.UserId == userId && er.EventId == id); + + if (registration is null) + return Results.Json(new { success = false, error_msg = "Registration not found." }); + + dbContext.EventRegistrations.Remove(registration); + await dbContext.SaveChangesAsync(); + + return Results.Json(new { success = true }); + }); + + return group; + } + } +} diff --git a/WebApp/Mapping/EventRegistrationMapping.cs b/WebApp/Mapping/EventRegistrationMapping.cs new file mode 100644 index 0000000..5f76622 --- /dev/null +++ b/WebApp/Mapping/EventRegistrationMapping.cs @@ -0,0 +1,17 @@ +using WebApp.DTOs; +using WebApp.Entities; + +namespace WebApp.Mapping +{ + public static class EventRegistrationMapping + { + public static EventRegistrationDto ToEventRegistrationDto(this EventRegistration er) + { + return new EventRegistrationDto( + er.EventId, + er.UserId, + er.RegisteredAt + ); + } + } +} diff --git a/WebApp/Program.cs b/WebApp/Program.cs index e92ad18..71e6c9d 100644 --- a/WebApp/Program.cs +++ b/WebApp/Program.cs @@ -54,5 +54,6 @@ app.MapEventsEndpoints(); app.MapOrganizationsEndpoints(); app.MapAuthEndpoints(); app.MapSkillsEndpoints(); +app.MapEventsRegistrationEndpoints(); app.Run(); diff --git a/WebApp/ts/eventView.ts b/WebApp/ts/eventView.ts index 922d950..a79e6ee 100644 --- a/WebApp/ts/eventView.ts +++ b/WebApp/ts/eventView.ts @@ -1,4 +1,4 @@ -import { getEvent, getMyAccount, unhideElementById } from './generalUseHelpers.js'; +import { getEvent, getMyAccount, unhideElementById, getMyRegisteredEventIds } from './generalUseHelpers.js'; const queryString = window.location.search; const urlParams = new URLSearchParams(queryString); @@ -9,6 +9,8 @@ document.addEventListener("DOMContentLoaded", async () => { var container = document.getElementById("mainContainer"); const modifyBtn = document.getElementById("editBtn"); const removeBtn = document.getElementById("removeBtn"); + const applyBtn = document.getElementById("applyBtn"); + const leaveBtn = document.getElementById("leaveBtn"); var org_id: number = -1; try { @@ -28,11 +30,11 @@ document.addEventListener("DOMContentLoaded", async () => { try { if (eventId) thisEvent = await getEvent(eventId); } catch (err) { - if (container !== null) container.innerHTML = `
To wydarzenie nie istnieje! Powrót ->
`; + if (container !== null) container.innerHTML = `To wydarzenie nie istnieje! Powr�t ->
`; } if (thisEvent == null) { - if (container !== null) container.innerHTML = `B³¹d we wczytywaniu wydarzenia. Powrót ->
`; + if (container !== null) container.innerHTML = `Błąd we wczytywaniu wydarzenia. Powrót ->
`; } else { const titleText = document.getElementById( "titleText") as HTMLElement; @@ -51,13 +53,20 @@ document.addEventListener("DOMContentLoaded", async () => { organizerText.innerHTML = "Organized by: " + thisEvent.organisationName; if (org_id == thisEvent.organisationId) { - // U¿ytkownik jest organizacj¹, która - // stworzy³a to wydarzenie + // Użytkownik jest organizacjÄ…, która + // stworzyÅ‚a to wydarzenie unhideElementById(document, "editBtn"); unhideElementById(document, "removeBtn"); } else if (org_id == -1) { - // U¿ytkownik jest wolontariuszem - unhideElementById(document, "applyBtn"); + // Użytkownik jest wolontariuszem + const registeredIds = await getMyRegisteredEventIds(); + const isRegistered = registeredIds.includes(Number(eventId)); + + if (isRegistered) { + unhideElementById(document, "leaveBtn"); + } else { + unhideElementById(document, "applyBtn"); + } } unhideElementById(document, "mainContainer"); @@ -76,7 +85,7 @@ document.addEventListener("DOMContentLoaded", async () => { if (!confirmed) return; try { - // Wysy³a ¿¹danie DELETE do API + // WysyÅ‚a żądanie DELETE do API const response = await fetch(`/api/events/${eventId}`, { method: "DELETE" }); @@ -94,4 +103,59 @@ document.addEventListener("DOMContentLoaded", async () => { }); } -}); \ No newline at end of file + if (applyBtn) { + applyBtn.addEventListener("click", async (e) => { + try { + const response = await fetch(`/api/events/join/${eventId}`, { + method: "POST", + headers: { + "Content-Type": "application/json" + }, + }); + + const result: { + success: boolean; + error_msg?: string; + } = await response.json(); + + if (result.success) { + window.location.href = `/view.html?event=${eventId}`; + } else { + alert(`Error: ${result.error_msg ?? "Unknown error occurred."}`); + } + } catch (error) { + console.error("Failed to apply:", error); + alert("Failed to apply."); + } + }); + } + + if (leaveBtn) { + leaveBtn.addEventListener("click", async (e) => { + try { + const response = await fetch(`/api/events/leave/${eventId}`, { + method: "POST", + headers: { + "Content-Type": "application/json" + }, + }); + + const result: { + success: boolean; + error_msg?: string; + } = await response.json(); + + if (result.success) { + window.location.href = `/view.html?event=${eventId}`; + } else { + alert(`Error: ${result.error_msg ?? "Unknown error occurred."}`); + } + + } catch (error) { + console.error("Failed to leave:", error) + alert("Failed to leave.") + } + }); + } + +}); diff --git a/WebApp/ts/generalUseHelpers.ts b/WebApp/ts/generalUseHelpers.ts index f89acfc..8e24a74 100644 --- a/WebApp/ts/generalUseHelpers.ts +++ b/WebApp/ts/generalUseHelpers.ts @@ -36,9 +36,20 @@ export async function getEvent(id: string): PromiseTo wydarzenie nie istnieje! Powrót ->
`; + container.innerHTML = `To wydarzenie nie istnieje! Powr�t ->
`; } if (thisEvent == null) { if (container !== null) @@ -63,7 +65,14 @@ document.addEventListener("DOMContentLoaded", () => __awaiter(void 0, void 0, vo } else if (org_id == -1) { // Użytkownik jest wolontariuszem - unhideElementById(document, "applyBtn"); + const registeredIds = yield getMyRegisteredEventIds(); + const isRegistered = registeredIds.includes(Number(eventId)); + if (isRegistered) { + unhideElementById(document, "leaveBtn"); + } + else { + unhideElementById(document, "applyBtn"); + } } unhideElementById(document, "mainContainer"); } @@ -96,4 +105,52 @@ document.addEventListener("DOMContentLoaded", () => __awaiter(void 0, void 0, vo } })); } + if (applyBtn) { + applyBtn.addEventListener("click", (e) => __awaiter(void 0, void 0, void 0, function* () { + var _b; + try { + const response = yield fetch(`/api/events/join/${eventId}`, { + method: "POST", + headers: { + "Content-Type": "application/json" + }, + }); + const result = yield response.json(); + if (result.success) { + window.location.href = `/view.html?event=${eventId}`; + } + else { + alert(`Error: ${(_b = result.error_msg) !== null && _b !== void 0 ? _b : "Unknown error occurred."}`); + } + } + catch (error) { + console.error("Failed to apply:", error); + alert("Failed to apply."); + } + })); + } + if (leaveBtn) { + leaveBtn.addEventListener("click", (e) => __awaiter(void 0, void 0, void 0, function* () { + var _c; + try { + const response = yield fetch(`/api/events/leave/${eventId}`, { + method: "POST", + headers: { + "Content-Type": "application/json" + }, + }); + const result = yield response.json(); + if (result.success) { + window.location.href = `/view.html?event=${eventId}`; + } + else { + alert(`Error: ${(_c = result.error_msg) !== null && _c !== void 0 ? _c : "Unknown error occurred."}`); + } + } + catch (error) { + console.error("Failed to leave:", error); + alert("Failed to leave."); + } + })); + } })); diff --git a/WebApp/wwwroot/js/generalUseHelpers.js b/WebApp/wwwroot/js/generalUseHelpers.js index 137fd53..264c476 100644 --- a/WebApp/wwwroot/js/generalUseHelpers.js +++ b/WebApp/wwwroot/js/generalUseHelpers.js @@ -35,3 +35,13 @@ export function getMyAccount() { return data; }); } +export function getMyRegisteredEventIds() { + return __awaiter(this, void 0, void 0, function* () { + const res = yield fetch("/api/auth/my_events"); + if (!res.ok) { + throw Error("Użytkownik niezalogowany!"); + } + const events = yield res.json(); + return events.map((event) => event.eventId); + }); +} diff --git a/WebApp/wwwroot/modify.html b/WebApp/wwwroot/modify.html index 1c4690f..5104bce 100644 --- a/WebApp/wwwroot/modify.html +++ b/WebApp/wwwroot/modify.html @@ -80,6 +80,7 @@ +diff --git a/WebApp/wwwroot/view.html b/WebApp/wwwroot/view.html index 9fb655e..3f804b0 100644 --- a/WebApp/wwwroot/view.html +++ b/WebApp/wwwroot/view.html @@ -1,4 +1,4 @@ - +
@@ -64,6 +64,7 @@
+