using System.Security.Cryptography; using System.Text; using Microsoft.EntityFrameworkCore; using WebApp.Data; using WebApp.DTOs; using WebApp.Entities; using WebApp.Mapping; namespace WebApp.Endpoints { public static class AuthEndpoints { public static RouteGroupBuilder MapAuthEndpoints(this WebApplication app) { const string GetUserEndpointName = "GetUser"; var group = app.MapGroup("api/auth") .WithParameterValidation(); group.MapPost("/login", async (LoginDto dto, ApplicationDbContext context, GeneralUseHelpers guh) => { var user = await context.WebUsers.FirstOrDefaultAsync(u => u.Email == dto.Email); string hashedPassword = HashPasswordSHA512(dto.Password); if (user == null || user.Password != hashedPassword) { return Results.Json(new { message = "Wrong email or password." }, statusCode: 401); } var token = await guh.CreateNewToken(user.UserId); return Results.Ok(new { message = "Login successful.", token = token.Value }); }); group.MapPost("/logout", async (HttpContext httpContext, GeneralUseHelpers guh) => { var token = await guh.GetTokenFromHTTPContext(httpContext); if (token == null) { return Results.Json(new { message = "No valid token found." }, statusCode: 401); } await guh.DeleteToken(token); httpContext.Response.Cookies.Delete("token"); return Results.Ok(new { success = true }); }); group.MapGet("/my_account", async (HttpContext httpContext, GeneralUseHelpers guh) => { var token = await guh.GetTokenFromHTTPContext(httpContext); if(token == null) { return Results.Json(new { message = "No valid token found." }, statusCode: 401); } User? user = await guh.GetUserFromToken(token); if(user == null) { return Results.Json(new {message = "No user found."}, statusCode: 404); } Organisation? org = await guh.GetOrganisationFromUserId(user.UserId); if (org is not null) return Results.Ok(user.ToUserSummaryWithOrgIdDto(org.OrganisationId)); return Results.Ok(user.ToUserSummaryDto()); }) .WithName(GetUserEndpointName); group.MapGet("/my_events", async (HttpContext httpContext, GeneralUseHelpers guh, ApplicationDbContext context) => { var token = await guh.GetTokenFromHTTPContext(httpContext); if (token == null) { return Results.Json(new { message = "No valid token found." }, statusCode: 401); } User? user = await guh.GetUserFromToken(token); if (user == null) { return Results.Json(new { message = "No user found." }, statusCode: 404); } if(!user.IsOrganisation) { var events = await context.EventRegistrations .Where(er => er.UserId == user.UserId) .Select(er => er.Event.ToEventSummaryNoErDto()) .ToListAsync(); return Results.Ok(events); } else { var org = await context.Organisations.FirstOrDefaultAsync(o => o.UserId == user.UserId); if(org == null) { return Results.Json(new { message = "No organisation found for this user." }, statusCode: 404); } var events = await context.Events .Where(e => e.OrganisationId == org.OrganisationId) .Select(e => e.ToEventSummaryDto()) .ToListAsync(); return Results.Ok(events); } }); group.MapPost("/add_skill", async (SingleSkillDto dto, HttpContext httpContext, ApplicationDbContext context, GeneralUseHelpers guh) => { // Uzyskaj użytkownika z tokenu Token? token = await guh.GetTokenFromHTTPContext(httpContext); User? user = await guh.GetUserFromToken(token); // Tylko wolontariusze powinno móc dodawać swoje skille if (user == null || user.IsOrganisation) { return Results.Json(new { message = "Unauthorized" }, statusCode: 401); } // Szukamy skilla w bazie o ID takim, jak w otrzymanym DTO Skill? skill = await context.Skills.FindAsync(dto.Skill); if (skill is null) { return Results.Json(new { message = "Skill not found" }, statusCode: 404); } // Sprawdzamy, czy ten użytkownik nie ma już takiego skilla. Jeżeli ma, nie ma sensu dodawać go kilkukrotnie. VolunteerSkill? vs = await context.VolunteerSkills.FirstOrDefaultAsync(v => v.UserId == user.UserId && v.SkillId == dto.Skill); if (vs is null) { // Nie ma - zatem musimy dodać nowy VolunteerSkill do bazy VolunteerSkill newVs = dto.ToVolunteerSkillEntity(user.UserId); context.VolunteerSkills.Add(newVs); await context.SaveChangesAsync(); } else { // Ma - (ta para UserId <-> SkillId już istnieje w bazie) użytkownik już ma ten skill return Results.Json(new { message = "You already have this skill!" }, statusCode: 400); } return Results.Json(new { message = "Skill added successfully!" }, statusCode: 201); }); group.MapPost("/remove_skill", async (SingleSkillDto dto, HttpContext httpContext, ApplicationDbContext context, GeneralUseHelpers guh) => { // Uzyskaj użytkownika z tokenu Token? token = await guh.GetTokenFromHTTPContext(httpContext); User? user = await guh.GetUserFromToken(token); // Tylko wolontariusze powinien móc usuwac swoje skille if (user == null || user.IsOrganisation) { return Results.Json(new { message = "Unauthorized" }, statusCode: 401); } // Szukamy skilla w bazie o ID takim, jak w otrzymanym DTO Skill? skill = await context.Skills.FindAsync(dto.Skill); if (skill is null) { return Results.Json(new { message = "Skill not found" }, statusCode: 404); } // Sprawdzamy, czy ten użytkownik ma już taki skill. Jeżeli nie ma, nie ma sensu usuwac go kilkukrotnie. VolunteerSkill? vs = await context.VolunteerSkills.FirstOrDefaultAsync(v => v.UserId == user.UserId && v.SkillId == dto.Skill); if (vs is not null) { // Nie ma - zatem musimy dodać nowy VolunteerSkill do bazy VolunteerSkill newVs = dto.ToVolunteerSkillEntity(user.UserId); await context.VolunteerSkills.Where(v => v.SkillId == dto.Skill) .ExecuteDeleteAsync(); } else { // Ma - (ta para UserId <-> SkillId już istnieje w bazie) użytkownik już ma ten skill return Results.Json(new { message = "You don't have this skill" }, statusCode: 400); } return Results.Json(new { message = "Skill deleted successfully!" }, statusCode: 201); }); group.MapGet("/get_skills", async (HttpContext httpContext, ApplicationDbContext context, GeneralUseHelpers guh) => { // Uzyskaj użytkownika z tokenu Token? token = await guh.GetTokenFromHTTPContext(httpContext); User? user = await guh.GetUserFromToken(token); // Sprawdź, czy użytkownik istnieje i nie jest organizacją if (user == null || user.IsOrganisation) { return Results.Json(new { message = "Unauthorized" }, statusCode: 401); } // Pobierz skille wolontariusza var skills = await context.VolunteerSkills .Where(vs => vs.UserId == user.UserId) .Include(vs => vs.Skill) .Select(vs => new { skillId = vs.Skill.SkillId, skillName = vs.Skill.Name }) .ToListAsync(); return Results.Json(skills); }); return group; } static string HashPasswordSHA512(string password) { using (var sha512 = SHA512.Create()) { byte[] bytes = Encoding.ASCII.GetBytes(password); byte[] hash = sha512.ComputeHash(bytes); string hashstring = BitConverter.ToString(hash).Replace("-", "").ToLower(); return hashstring; } } } }