| 
									
										
										
										
											2025-08-14 13:12:16 -03:00
										 |  |  | using Elecciones.Database; | 
					
						
							|  |  |  | using Microsoft.EntityFrameworkCore; | 
					
						
							| 
									
										
										
										
											2025-08-15 17:31:51 -03:00
										 |  |  | using Serilog; | 
					
						
							| 
									
										
										
										
											2025-08-29 09:54:22 -03:00
										 |  |  | using Elecciones.Core.Services; | 
					
						
							|  |  |  | using Elecciones.Infrastructure.Services; | 
					
						
							|  |  |  | using System.Text; | 
					
						
							|  |  |  | using Microsoft.AspNetCore.Authentication.JwtBearer; | 
					
						
							|  |  |  | using Microsoft.IdentityModel.Tokens; | 
					
						
							|  |  |  | using Elecciones.Database.Entities; | 
					
						
							|  |  |  | using System.Text.Json.Serialization; | 
					
						
							| 
									
										
										
										
											2025-08-14 13:12:16 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-15 17:31:51 -03:00
										 |  |  | // Esta es la estructura estándar y recomendada. | 
					
						
							| 
									
										
										
										
											2025-08-14 12:37:57 -03:00
										 |  |  | var builder = WebApplication.CreateBuilder(args); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-15 17:31:51 -03:00
										 |  |  | // 1. Configurar Serilog. Esta es la forma correcta de integrarlo. | 
					
						
							|  |  |  | builder.Host.UseSerilog((context, services, configuration) => configuration | 
					
						
							|  |  |  |     .ReadFrom.Configuration(context.Configuration) | 
					
						
							|  |  |  |     .ReadFrom.Services(services) | 
					
						
							|  |  |  |     .Enrich.FromLogContext() | 
					
						
							|  |  |  |     .WriteTo.Console() | 
					
						
							|  |  |  |     .WriteTo.File("logs/api-.log", rollingInterval: RollingInterval.Day)); | 
					
						
							| 
									
										
										
										
											2025-08-14 13:12:16 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-15 17:31:51 -03:00
										 |  |  | // 2. Añadir servicios al contenedor. | 
					
						
							| 
									
										
										
										
											2025-08-14 13:12:16 -03:00
										 |  |  | var connectionString = builder.Configuration.GetConnectionString("DefaultConnection"); | 
					
						
							|  |  |  | builder.Services.AddDbContext<EleccionesDbContext>(options => | 
					
						
							|  |  |  |     options.UseSqlServer(connectionString)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-29 09:54:22 -03:00
										 |  |  | builder.Services.AddScoped<IPasswordHasher, PasswordHasher>(); | 
					
						
							| 
									
										
										
										
											2025-08-14 13:12:16 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-29 09:54:22 -03:00
										 |  |  | builder.Services.AddControllers().AddJsonOptions(options => | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     // Esto le dice al serializador que maneje las referencias circulares | 
					
						
							|  |  |  |     options.JsonSerializerOptions.ReferenceHandler = ReferenceHandler.IgnoreCycles; | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var MyAllowSpecificOrigins = "_myAllowSpecificOrigins"; | 
					
						
							| 
									
										
										
										
											2025-08-14 13:12:16 -03:00
										 |  |  | builder.Services.AddCors(options => | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2025-08-29 09:54:22 -03:00
										 |  |  |     options.AddPolicy(name: MyAllowSpecificOrigins, | 
					
						
							|  |  |  |                       policy => | 
					
						
							|  |  |  |                       { | 
					
						
							|  |  |  |                           policy.WithOrigins( | 
					
						
							|  |  |  |                               "http://localhost:5173", // Para widgets | 
					
						
							|  |  |  |                               "http://localhost:5174"  // Para admin | 
					
						
							|  |  |  |                           )  | 
					
						
							|  |  |  |                           .AllowAnyHeader() | 
					
						
							|  |  |  |                           .AllowAnyMethod(); | 
					
						
							|  |  |  |                       }); | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) | 
					
						
							|  |  |  |     .AddJwtBearer(options => | 
					
						
							| 
									
										
										
										
											2025-08-14 13:12:16 -03:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2025-08-29 09:54:22 -03:00
										 |  |  |         options.TokenValidationParameters = new TokenValidationParameters | 
					
						
							| 
									
										
										
										
											2025-08-14 15:51:19 -03:00
										 |  |  |         { | 
					
						
							| 
									
										
										
										
											2025-08-29 09:54:22 -03:00
										 |  |  |             ValidateIssuer = true, | 
					
						
							|  |  |  |             ValidateAudience = true, | 
					
						
							|  |  |  |             ValidateLifetime = true, | 
					
						
							|  |  |  |             ValidateIssuerSigningKey = true, | 
					
						
							|  |  |  |             ValidIssuer = builder.Configuration["Jwt:Issuer"], | 
					
						
							|  |  |  |             ValidAudience = builder.Configuration["Jwt:Audience"], | 
					
						
							|  |  |  |             IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"]!)) | 
					
						
							|  |  |  |         }; | 
					
						
							| 
									
										
										
										
											2025-08-14 13:12:16 -03:00
										 |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | builder.Services.AddEndpointsApiExplorer(); | 
					
						
							|  |  |  | builder.Services.AddSwaggerGen(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-14 12:37:57 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-15 17:31:51 -03:00
										 |  |  | // 3. Construir la aplicación. | 
					
						
							| 
									
										
										
										
											2025-08-14 12:37:57 -03:00
										 |  |  | var app = builder.Build(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-29 09:54:22 -03:00
										 |  |  | // Seeder para el usuario admin | 
					
						
							|  |  |  | using (var scope = app.Services.CreateScope()) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     var services = scope.ServiceProvider; | 
					
						
							|  |  |  |     try | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         var context = services.GetRequiredService<EleccionesDbContext>(); | 
					
						
							|  |  |  |         var hasher = services.GetRequiredService<IPasswordHasher>(); | 
					
						
							|  |  |  |         if (!context.AdminUsers.Any()) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             var (hash, salt) = hasher.HashPassword("PTP847elec"); | 
					
						
							|  |  |  |             context.AdminUsers.Add(new Elecciones.Database.Entities.AdminUser | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 Username = "admin", | 
					
						
							|  |  |  |                 PasswordHash = hash, | 
					
						
							|  |  |  |                 PasswordSalt = salt | 
					
						
							|  |  |  |             }); | 
					
						
							|  |  |  |             context.SaveChanges(); | 
					
						
							|  |  |  |             Console.WriteLine("--> Admin user seeded."); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     catch (Exception ex) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         var logger = services.GetRequiredService<ILogger<Program>>(); | 
					
						
							|  |  |  |         logger.LogError(ex, "An error occurred while seeding the database."); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Seeder para las bancas vacías | 
					
						
							|  |  |  | using (var scope = app.Services.CreateScope()) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     var services = scope.ServiceProvider; | 
					
						
							|  |  |  |     var context = services.GetRequiredService<EleccionesDbContext>(); | 
					
						
							|  |  |  |     if (!context.Bancadas.Any()) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         var bancas = new List<Bancada>(); | 
					
						
							|  |  |  |         // 92 bancas de diputados | 
					
						
							|  |  |  |         for (int i = 0; i < 92; i++) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             bancas.Add(new Bancada { Camara = Elecciones.Core.Enums.TipoCamara.Diputados }); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         // 46 bancas de senadores | 
					
						
							|  |  |  |         for (int i = 0; i < 46; i++) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             bancas.Add(new Bancada { Camara = Elecciones.Core.Enums.TipoCamara.Senadores }); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         context.Bancadas.AddRange(bancas); | 
					
						
							|  |  |  |         context.SaveChanges(); | 
					
						
							|  |  |  |         Console.WriteLine("--> Seeded 138 empty bancas."); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Seeder para las configuraciones por defecto | 
					
						
							|  |  |  | using (var scope = app.Services.CreateScope()) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     var services = scope.ServiceProvider; | 
					
						
							|  |  |  |     var context = services.GetRequiredService<EleccionesDbContext>(); | 
					
						
							|  |  |  |     if (!context.Configuraciones.Any(c => c.Clave == "MostrarOcupantes")) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         context.Configuraciones.Add(new Configuracion { Clave = "MostrarOcupantes", Valor = "true" }); | 
					
						
							|  |  |  |         context.SaveChanges(); | 
					
						
							|  |  |  |         Console.WriteLine("--> Seeded default configuration 'MostrarOcupantes'."); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Configurar el pipeline de peticiones HTTP. | 
					
						
							| 
									
										
										
										
											2025-08-15 17:31:51 -03:00
										 |  |  | // Añadimos el logging de peticiones de Serilog aquí. | 
					
						
							|  |  |  | app.UseSerilogRequestLogging(); | 
					
						
							| 
									
										
										
										
											2025-08-14 13:12:16 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-14 12:37:57 -03:00
										 |  |  | if (app.Environment.IsDevelopment()) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2025-08-14 13:12:16 -03:00
										 |  |  |     app.UseSwagger(); | 
					
						
							|  |  |  |     app.UseSwaggerUI(); | 
					
						
							| 
									
										
										
										
											2025-08-14 12:37:57 -03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-29 09:54:22 -03:00
										 |  |  | // 1. Redirección a HTTPS (si se usa) | 
					
						
							|  |  |  | //app.UseHttpsRedirection(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // 2. Middleware de Enrutamiento. ¡CLAVE! | 
					
						
							|  |  |  | //    Determina a qué endpoint irá la petición. | 
					
						
							|  |  |  | app.UseRouting(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // 3. Middleware de CORS. | 
					
						
							|  |  |  | //    Ahora se ejecuta sabiendo a qué endpoint se dirige la petición. | 
					
						
							|  |  |  | app.UseCors(MyAllowSpecificOrigins); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // 4. Middleware de Autenticación. | 
					
						
							|  |  |  | //    Identifica quién es el usuario a partir del token. | 
					
						
							|  |  |  | app.UseAuthentication(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // 5. Middleware de Autorización. | 
					
						
							|  |  |  | //    Verifica si el usuario identificado tiene permiso para acceder al endpoint. | 
					
						
							| 
									
										
										
										
											2025-08-14 13:12:16 -03:00
										 |  |  | app.UseAuthorization(); | 
					
						
							| 
									
										
										
										
											2025-08-29 09:54:22 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | // 6. Mapea los controladores a los endpoints que el enrutador descubrió. | 
					
						
							| 
									
										
										
										
											2025-08-14 13:12:16 -03:00
										 |  |  | app.MapControllers(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-15 17:31:51 -03:00
										 |  |  | // 5. Ejecutar la aplicación. | 
					
						
							| 
									
										
										
										
											2025-08-14 13:12:16 -03:00
										 |  |  | app.Run(); |