using MediatR; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; using Nashel.Modules.Identity.Application.Commands; using Nashel.Modules.Identity.Application.Queries; using Nashel.Modules.Identity.Application.Queries.GetProfile; namespace Nashel.Modules.Identity.Presentation.Endpoints; public static class IdentityEndpoints { public static void MapIdentityEndpoints(this IEndpointRouteBuilder app) { var authGroup = app.MapGroup("/api/auth").WithTags("Auth"); authGroup.MapPost("/register", async (RegisterUserCommand command, ISender sender) => { var result = await sender.Send(command); return Results.Ok(result); }) .WithName("Register") .WithOpenApi(operation => new(operation) { Summary = "Регистрация пользователя" }); authGroup.MapPost("/login", async (LoginCommand command, ISender sender) => { var token = await sender.Send(command); return Results.Ok(new LoginResponse(token, token)); // Пока что возвращаем один токен для обоих полей }) .WithName("Login") .WithOpenApi(operation => new(operation) { Summary = "Вход в систему" }); var profileGroup = app.MapGroup("/api/profile").WithTags("Profile").RequireAuthorization(); profileGroup.MapGet("/", async (ISender sender) => { var profile = await sender.Send(new GetProfileQuery()); return Results.Ok(profile); }) .WithName("GetProfile") .WithOpenApi(operation => new(operation) { Summary = "Получить профиль" }); profileGroup.MapPut("/", async (UpdateProfileCommand command, ISender sender) => { await sender.Send(command); return Results.NoContent(); }) .WithName("UpdateProfile") .WithOpenApi(operation => new(operation) { Summary = "Обновить профиль" }); profileGroup.MapPost("/change-phone", async (ChangePhoneNumberCommand command, ISender sender) => { await sender.Send(command); return Results.NoContent(); }) .WithName("ChangePhone") .WithOpenApi(operation => new(operation) { Summary = "Сменить номер телефона" }); profileGroup.MapPost("/become-performer", async (BecomePerformerRequest request, ISender sender) => { Console.WriteLine($"[BecomePerformerEndpoint] Request received"); Console.WriteLine($"[BecomePerformerEndpoint] Description: {request.Description?.Substring(0, Math.Min(50, request.Description.Length))}..."); Console.WriteLine($"[BecomePerformerEndpoint] Competencies count: {request.Competencies?.Count ?? 0}"); Console.WriteLine($"[BecomePerformerEndpoint] Location: {request.Location}"); Console.WriteLine($"[BecomePerformerEndpoint] IsAlwaysReady: {request.IsAlwaysReady}"); await sender.Send(new BecomePerformerCommand { Description = request.Description, CompetencyNames = request.Competencies, Location = request.Location, CurrentLocation = request.CurrentLocation, IsAlwaysReady = request.IsAlwaysReady, WorkingDays = request.WorkingDays }); Console.WriteLine($"[BecomePerformerEndpoint] Successfully completed"); return Results.Ok(); }) .WithName("BecomePerformer") .WithOpenApi(operation => new(operation) { Summary = "Стать исполнителем" }); profileGroup.MapPost("/avatar", async (IFormFile file, ISender sender) => { var url = await sender.Send(new UploadAvatarCommand(file)); return Results.Ok(new { avatarUrl = url }); }) .WithName("UploadAvatar") .WithOpenApi(operation => new(operation) { Summary = "Загрузить аватар" }) .DisableAntiforgery(); profileGroup.MapPut("/competencies", async (UpdateCompetenciesRequest request, ISender sender) => { await sender.Send(new UpdateProfileCompetenciesCommand(request.Competencies)); return Results.NoContent(); }) .WithName("UpdateCompetencies") .WithOpenApi(operation => new(operation) { Summary = "Обновить компетенции" }); var competenciesGroup = app.MapGroup("/api/competencies").WithTags("Competencies"); competenciesGroup.MapGet("/search", async (string q, ISender sender) => { var results = await sender.Send(new SearchCompetenciesQuery(q)); return Results.Ok(results); }) .WithName("SearchCompetencies") .WithOpenApi(operation => new(operation) { Summary = "Поиск компетенций" }); // Эндпоинт для смены пароля profileGroup.MapPost("/change-password", async (ChangePasswordRequest request, ISender sender) => { await sender.Send(new ChangePasswordCommand { AccountId = request.AccountId, OldPassword = request.OldPassword, NewPassword = request.NewPassword }); return Results.Ok(new { success = true, message = "Пароль успешно изменён" }); }) .WithName("ChangePassword") .WithOpenApi(operation => new(operation) { Summary = "Сменить пароль" }); // Эндпоинт для обновления локации profileGroup.MapPut("/location", async (UpdateLocationRequest request, ISender sender) => { await sender.Send(new UpdateLocationCommand { AccountId = request.AccountId, Location = request.Location, CurrentLocation = request.CurrentLocation }); return Results.NoContent(); }) .WithName("UpdateLocation") .WithOpenApi(operation => new(operation) { Summary = "Обновить локацию" }); // Эндпоинт для обновления расписания profileGroup.MapPut("/schedule", async (UpdateScheduleRequest request, ISender sender) => { await sender.Send(new UpdateScheduleCommand { AccountId = request.AccountId, IsAlwaysReady = request.IsAlwaysReady, WorkingDaysJson = request.WorkingDaysJson ?? "[]" }); return Results.NoContent(); }) .WithName("UpdateSchedule") .WithOpenApi(operation => new(operation) { Summary = "Обновить расписание" }); } } public record LoginResponse(string AccessToken, string RefreshToken); public record UpdateCompetenciesRequest(List Competencies); public record BecomePerformerRequest( string Description, List Competencies, string? Location, string? CurrentLocation, bool IsAlwaysReady, string? WorkingDays ); public record ChangePasswordRequest( Guid AccountId, string OldPassword, string NewPassword ); public record UpdateLocationRequest( Guid AccountId, string? Location, string? CurrentLocation ); public record UpdateScheduleRequest( Guid AccountId, bool IsAlwaysReady, string? WorkingDaysJson );