fix: program.cs
This commit is contained in:
parent
447d2863f4
commit
346aa86216
528
Program.cs
528
Program.cs
@ -1,237 +1,238 @@
|
|||||||
using BCards.Web.Configuration;
|
|
||||||
using BCards.Web.Services;
|
|
||||||
using BCards.Web.Repositories;
|
|
||||||
using Microsoft.AspNetCore.Authentication.Cookies;
|
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||||
using Microsoft.AspNetCore.Authentication.Google;
|
using Microsoft.AspNetCore.Authentication.Google;
|
||||||
using Microsoft.AspNetCore.Authentication.MicrosoftAccount;
|
using Microsoft.AspNetCore.Authentication.MicrosoftAccount;
|
||||||
using Microsoft.AspNetCore.Localization;
|
using Microsoft.AspNetCore.Localization;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.AspNetCore.StaticFiles;
|
||||||
|
using Microsoft.Extensions.Caching.Distributed;
|
||||||
|
using Microsoft.Extensions.Localization;
|
||||||
using MongoDB.Driver;
|
using MongoDB.Driver;
|
||||||
using System.Globalization;
|
using QRRapidoApp.Data;
|
||||||
|
using QRRapidoApp.Middleware;
|
||||||
|
using QRRapidoApp.Providers;
|
||||||
|
using QRRapidoApp.Services;
|
||||||
|
using QRRapidoApp.Services.Monitoring;
|
||||||
|
using QRRapidoApp.Services.HealthChecks;
|
||||||
|
using StackExchange.Redis;
|
||||||
using Stripe;
|
using Stripe;
|
||||||
using Microsoft.AspNetCore.Authentication.OAuth;
|
using System.Globalization;
|
||||||
using SendGrid;
|
using Serilog;
|
||||||
using BCards.Web.Middleware;
|
using Serilog.Events;
|
||||||
using Microsoft.AspNetCore.Http.Features;
|
using Serilog.Sinks.SystemConsole.Themes;
|
||||||
|
using Microsoft.AspNetCore.Mvc.Razor;
|
||||||
using Microsoft.AspNetCore.HttpOverrides;
|
using Microsoft.AspNetCore.HttpOverrides;
|
||||||
|
|
||||||
var builder = WebApplication.CreateBuilder(args);
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
|
|
||||||
// 🔥 CONFIGURAR FORWARDED HEADERS NO BUILDER
|
// Configure Serilog
|
||||||
builder.Services.Configure<ForwardedHeadersOptions>(options =>
|
Log.Logger = new LoggerConfiguration()
|
||||||
{
|
.ReadFrom.Configuration(builder.Configuration)
|
||||||
options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
|
.Enrich.FromLogContext()
|
||||||
options.RequireHeaderSymmetry = false;
|
.Enrich.WithEnvironmentName()
|
||||||
options.KnownNetworks.Clear();
|
.Enrich.WithProcessId()
|
||||||
options.KnownProxies.Clear();
|
.Enrich.WithThreadId()
|
||||||
// 🚨 PERMITIR QUALQUER PROXY (NGINX)
|
.Enrich.WithProperty("ApplicationName", builder.Configuration["ApplicationName"] ?? "QRRapido")
|
||||||
options.ForwardLimit = null;
|
.Enrich.WithProperty("Environment", "Dev")
|
||||||
});
|
.WriteTo.Async(a => a.Console(
|
||||||
|
outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj} {Properties:j}{NewLine}{Exception}",
|
||||||
|
theme: AnsiConsoleTheme.Code))
|
||||||
|
.WriteTo.Async(a => a.Seq(builder.Configuration["Serilog:SeqUrl"],
|
||||||
|
apiKey: builder.Configuration["Serilog:ApiKey"]=="" ? null : builder.Configuration["Serilog:ApiKey"]))
|
||||||
|
.CreateLogger();
|
||||||
|
|
||||||
// Add services to the container.
|
builder.Host.UseSerilog();
|
||||||
|
|
||||||
|
// Add services to the container
|
||||||
builder.Services.AddControllersWithViews()
|
builder.Services.AddControllersWithViews()
|
||||||
.AddRazorRuntimeCompilation()
|
.AddViewLocalization(Microsoft.AspNetCore.Mvc.Razor.LanguageViewLocationExpanderFormat.Suffix)
|
||||||
.AddViewLocalization()
|
|
||||||
.AddDataAnnotationsLocalization();
|
.AddDataAnnotationsLocalization();
|
||||||
|
|
||||||
// MongoDB Configuration
|
builder.Services.AddDistributedMemoryCache(); // Armazena os dados da sess<73>o na mem<65>ria
|
||||||
builder.Services.Configure<MongoDbSettings>(
|
builder.Services.AddSession(options =>
|
||||||
builder.Configuration.GetSection("MongoDb"));
|
|
||||||
|
|
||||||
builder.Services.AddSingleton<IMongoClient>(serviceProvider =>
|
|
||||||
{
|
{
|
||||||
var settings = serviceProvider.GetRequiredService<IOptions<MongoDbSettings>>().Value;
|
options.Cookie.HttpOnly = true;
|
||||||
return new MongoClient(settings.ConnectionString);
|
options.Cookie.IsEssential = true;
|
||||||
|
options.IdleTimeout = TimeSpan.FromMinutes(30); // Tempo de expira<72><61>o
|
||||||
});
|
});
|
||||||
|
|
||||||
builder.Services.AddScoped(serviceProvider =>
|
// Add HttpClient for health checks
|
||||||
|
builder.Services.AddHttpClient();
|
||||||
|
|
||||||
|
// MongoDB Configuration - optional for development
|
||||||
|
var mongoConnectionString = builder.Configuration.GetConnectionString("MongoDB");
|
||||||
|
if (!string.IsNullOrEmpty(mongoConnectionString))
|
||||||
{
|
{
|
||||||
var client = serviceProvider.GetRequiredService<IMongoClient>();
|
try
|
||||||
var settings = serviceProvider.GetRequiredService<IOptions<MongoDbSettings>>().Value;
|
{
|
||||||
return client.GetDatabase(settings.DatabaseName);
|
builder.Services.AddSingleton<IMongoClient>(serviceProvider =>
|
||||||
});
|
{
|
||||||
|
return new MongoClient(mongoConnectionString);
|
||||||
|
});
|
||||||
|
builder.Services.AddScoped<MongoDbContext>();
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// MongoDB not available - services will handle gracefully
|
||||||
|
builder.Services.AddScoped<MongoDbContext>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Development mode without MongoDB
|
||||||
|
builder.Services.AddScoped<MongoDbContext>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cache Configuration - use Redis if available, otherwise memory cache
|
||||||
|
var redisConnectionString = builder.Configuration.GetConnectionString("Redis");
|
||||||
|
if (!string.IsNullOrEmpty(redisConnectionString))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
builder.Services.AddStackExchangeRedisCache(options =>
|
||||||
|
{
|
||||||
|
options.Configuration = redisConnectionString;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// Fallback to memory cache if Redis fails
|
||||||
|
builder.Services.AddMemoryCache();
|
||||||
|
builder.Services.AddSingleton<IDistributedCache, QRRapidoApp.Services.MemoryDistributedCacheWrapper>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Use memory cache when Redis is not configured
|
||||||
|
builder.Services.AddMemoryCache();
|
||||||
|
builder.Services.AddSingleton<IDistributedCache, MemoryDistributedCacheWrapper>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Authentication Configuration
|
||||||
|
builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
|
||||||
|
.AddCookie(options =>
|
||||||
|
{
|
||||||
|
options.LoginPath = "/Account/Login";
|
||||||
|
options.LogoutPath = "/Account/Logout";
|
||||||
|
options.ExpireTimeSpan = TimeSpan.FromDays(30);
|
||||||
|
options.SlidingExpiration = true;
|
||||||
|
})
|
||||||
|
.AddGoogle(options =>
|
||||||
|
{
|
||||||
|
options.ClientId = builder.Configuration["Authentication:Google:ClientId"];
|
||||||
|
options.ClientSecret = builder.Configuration["Authentication:Google:ClientSecret"];
|
||||||
|
|
||||||
|
// ADICIONE ESTAS LINHAS:
|
||||||
|
options.Events.OnRedirectToAuthorizationEndpoint = context =>
|
||||||
|
{
|
||||||
|
context.Response.Redirect(context.RedirectUri);
|
||||||
|
return Task.CompletedTask;
|
||||||
|
};
|
||||||
|
|
||||||
|
// OU use este método alternativo:
|
||||||
|
options.Scope.Add("email");
|
||||||
|
options.Scope.Add("profile");
|
||||||
|
options.SaveTokens = true;
|
||||||
|
}).AddMicrosoftAccount(MicrosoftAccountDefaults.AuthenticationScheme, options =>
|
||||||
|
{
|
||||||
|
options.ClientId = builder.Configuration["Authentication:Microsoft:ClientId"];
|
||||||
|
options.ClientSecret = builder.Configuration["Authentication:Microsoft:ClientSecret"];
|
||||||
|
|
||||||
|
options.AuthorizationEndpoint = "https://login.microsoftonline.com/common/oauth2/v2.0/authorize";
|
||||||
|
options.TokenEndpoint = "https://login.microsoftonline.com/common/oauth2/v2.0/token";
|
||||||
|
|
||||||
|
// Força sempre mostrar a tela de seleção de conta
|
||||||
|
options.Events.OnRedirectToAuthorizationEndpoint = context =>
|
||||||
|
{
|
||||||
|
context.Response.Redirect(context.RedirectUri + "&prompt=select_account");
|
||||||
|
return Task.CompletedTask;
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
// Stripe Configuration
|
// Stripe Configuration
|
||||||
builder.Services.Configure<StripeSettings>(
|
StripeConfiguration.ApiKey = builder.Configuration["Stripe:SecretKey"];
|
||||||
builder.Configuration.GetSection("Stripe"));
|
|
||||||
|
|
||||||
// OAuth Configuration
|
|
||||||
builder.Services.Configure<GoogleAuthSettings>(
|
|
||||||
builder.Configuration.GetSection("Authentication:Google"));
|
|
||||||
|
|
||||||
builder.Services.Configure<MicrosoftAuthSettings>(
|
|
||||||
builder.Configuration.GetSection("Authentication:Microsoft"));
|
|
||||||
|
|
||||||
// Adicionar configurações
|
|
||||||
builder.Services.Configure<ModerationSettings>(
|
|
||||||
builder.Configuration.GetSection("Moderation"));
|
|
||||||
|
|
||||||
// Authentication
|
|
||||||
builder.Services.AddAuthentication(options =>
|
|
||||||
{
|
|
||||||
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
|
|
||||||
options.DefaultChallengeScheme = GoogleDefaults.AuthenticationScheme;
|
|
||||||
})
|
|
||||||
.AddCookie(options =>
|
|
||||||
{
|
|
||||||
options.LoginPath = "/Auth/Login";
|
|
||||||
options.LogoutPath = "/Auth/Logout";
|
|
||||||
options.ExpireTimeSpan = TimeSpan.FromDays(30);
|
|
||||||
options.SlidingExpiration = true;
|
|
||||||
})
|
|
||||||
.AddGoogle(options =>
|
|
||||||
{
|
|
||||||
var googleAuth = builder.Configuration.GetSection("Authentication:Google");
|
|
||||||
options.ClientId = googleAuth["ClientId"] ?? "";
|
|
||||||
options.ClientSecret = googleAuth["ClientSecret"] ?? "";
|
|
||||||
})
|
|
||||||
.AddMicrosoftAccount(options =>
|
|
||||||
{
|
|
||||||
var msAuth = builder.Configuration.GetSection("Authentication:Microsoft");
|
|
||||||
options.ClientId = msAuth["ClientId"] ?? "";
|
|
||||||
options.ClientSecret = msAuth["ClientSecret"] ?? "";
|
|
||||||
options.CallbackPath = "/signin-microsoft";
|
|
||||||
|
|
||||||
// Força seleção de conta a cada login
|
|
||||||
options.AuthorizationEndpoint = "https://login.microsoftonline.com/common/oauth2/v2.0/authorize";
|
|
||||||
options.TokenEndpoint = "https://login.microsoftonline.com/common/oauth2/v2.0/token";
|
|
||||||
|
|
||||||
// 🔥 SOLUÇÃO RADICAL: SEMPRE FORÇAR HTTPS
|
|
||||||
options.Events = new OAuthEvents
|
|
||||||
{
|
|
||||||
OnRedirectToAuthorizationEndpoint = context =>
|
|
||||||
{
|
|
||||||
var logger = context.HttpContext.RequestServices.GetRequiredService<ILogger<Program>>();
|
|
||||||
|
|
||||||
// Debug info
|
|
||||||
logger.LogWarning($"=== MICROSOFT AUTH DEBUG ===");
|
|
||||||
logger.LogWarning($"Original RedirectUri: {context.RedirectUri}");
|
|
||||||
logger.LogWarning($"Request Scheme: {context.Request.Scheme}");
|
|
||||||
logger.LogWarning($"Request IsHttps: {context.Request.IsHttps}");
|
|
||||||
logger.LogWarning($"Request Host: {context.Request.Host}");
|
|
||||||
logger.LogWarning($"X-Forwarded-Proto: {context.Request.Headers["X-Forwarded-Proto"]}");
|
|
||||||
|
|
||||||
// 🚨 FORÇA HTTPS SEMPRE (exceto localhost)
|
|
||||||
var originalUri = context.RedirectUri;
|
|
||||||
|
|
||||||
// Se contém bcards.site, força HTTPS
|
|
||||||
if (originalUri.Contains("bcards.site"))
|
|
||||||
{
|
|
||||||
context.RedirectUri = originalUri
|
|
||||||
.Replace("http://bcards.site", "https://bcards.site")
|
|
||||||
.Replace("http%3A%2F%2Fbcards.site", "https%3A%2F%2Fbcards.site");
|
|
||||||
|
|
||||||
logger.LogWarning($"FORCED HTTPS - Modified RedirectUri: {context.RedirectUri}");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Adiciona prompt=login para forçar seleção de conta
|
|
||||||
var redirectUri = context.RedirectUri;
|
|
||||||
if (!redirectUri.Contains("prompt="))
|
|
||||||
{
|
|
||||||
redirectUri += "&prompt=login";
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.LogWarning($"Final RedirectUri: {redirectUri}");
|
|
||||||
|
|
||||||
context.Response.Redirect(redirectUri);
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
// Localization
|
// Localization
|
||||||
builder.Services.AddLocalization(options => options.ResourcesPath = "Resources");
|
builder.Services.AddLocalization(options => options.ResourcesPath = "");
|
||||||
|
//builder.Services.AddLocalization(options => options.ResourcesPath = "Resources");
|
||||||
builder.Services.Configure<RequestLocalizationOptions>(options =>
|
builder.Services.Configure<RequestLocalizationOptions>(options =>
|
||||||
{
|
{
|
||||||
var supportedCultures = new[]
|
var supportedCultures = new[]
|
||||||
{
|
{
|
||||||
new CultureInfo("pt-BR"),
|
new CultureInfo("pt-BR"),
|
||||||
new CultureInfo("es-ES")
|
new CultureInfo("es-PY"),
|
||||||
|
new CultureInfo("es")
|
||||||
};
|
};
|
||||||
|
|
||||||
options.DefaultRequestCulture = new RequestCulture("pt-BR");
|
options.DefaultRequestCulture = new RequestCulture("pt-BR", "pt-BR");
|
||||||
options.SupportedCultures = supportedCultures;
|
options.SupportedCultures = supportedCultures;
|
||||||
options.SupportedUICultures = supportedCultures;
|
options.SupportedUICultures = supportedCultures;
|
||||||
|
|
||||||
|
options.FallBackToParentCultures = false;
|
||||||
|
options.FallBackToParentUICultures = false;
|
||||||
|
|
||||||
|
// Clear default providers and add custom ones in priority order
|
||||||
|
options.RequestCultureProviders.Clear();
|
||||||
|
options.RequestCultureProviders.Add(new CustomRouteDataRequestCultureProvider());
|
||||||
|
options.RequestCultureProviders.Add(new QueryStringRequestCultureProvider());
|
||||||
|
options.RequestCultureProviders.Add(new CookieRequestCultureProvider());
|
||||||
});
|
});
|
||||||
|
|
||||||
// Register Services
|
// Custom Services
|
||||||
builder.Services.AddScoped<IUserRepository, UserRepository>();
|
builder.Services.AddScoped<IQRCodeService, QRRapidoService>();
|
||||||
builder.Services.AddScoped<IUserPageRepository, UserPageRepository>();
|
builder.Services.AddScoped<IUserService, UserService>();
|
||||||
builder.Services.AddScoped<ICategoryRepository, CategoryRepository>();
|
builder.Services.AddScoped<IPlanService, QRRapidoApp.Services.PlanService>();
|
||||||
builder.Services.AddScoped<ISubscriptionRepository, SubscriptionRepository>();
|
builder.Services.AddScoped<AdDisplayService>();
|
||||||
builder.Services.AddSingleton<IModerationAuthService, ModerationAuthService>();
|
builder.Services.AddScoped<StripeService>();
|
||||||
//builder.Services.AddScoped<IModerationAuthService, ModerationAuthService>();
|
builder.Services.AddScoped<LogoReadabilityAnalyzer>();
|
||||||
|
|
||||||
builder.Services.AddScoped<IUserPageService, UserPageService>();
|
|
||||||
builder.Services.AddScoped<IThemeService, ThemeService>();
|
|
||||||
builder.Services.AddScoped<ISeoService, SeoService>();
|
|
||||||
builder.Services.AddScoped<IAuthService, AuthService>();
|
|
||||||
builder.Services.AddScoped<IPaymentService, PaymentService>();
|
|
||||||
builder.Services.AddScoped<ICategoryService, CategoryService>();
|
|
||||||
builder.Services.AddScoped<IOpenGraphService, OpenGraphService>();
|
|
||||||
builder.Services.AddScoped<IModerationService, ModerationService>();
|
|
||||||
builder.Services.AddScoped<IEmailService, EmailService>();
|
|
||||||
|
|
||||||
// Image Storage Service
|
|
||||||
builder.Services.AddScoped<IImageStorageService, GridFSImageStorage>();
|
|
||||||
|
|
||||||
// Configure upload limits for file uploads
|
|
||||||
builder.Services.Configure<FormOptions>(options =>
|
|
||||||
{
|
|
||||||
options.MultipartBodyLengthLimit = 10 * 1024 * 1024; // 10MB for forms with files
|
|
||||||
options.ValueLengthLimit = int.MaxValue;
|
|
||||||
options.ValueCountLimit = int.MaxValue;
|
|
||||||
options.KeyLengthLimit = int.MaxValue;
|
|
||||||
});
|
|
||||||
|
|
||||||
// 🔥 NOVO: LivePage Services
|
|
||||||
builder.Services.AddScoped<ILivePageRepository, LivePageRepository>();
|
|
||||||
builder.Services.AddScoped<ILivePageService, LivePageService>();
|
|
||||||
|
|
||||||
// Add HttpClient for OpenGraphService
|
|
||||||
builder.Services.AddHttpClient<OpenGraphService>();
|
|
||||||
|
|
||||||
// Add SendGrid
|
|
||||||
builder.Services.AddSingleton<ISendGridClient>(provider =>
|
|
||||||
{
|
|
||||||
var apiKey = builder.Configuration["SendGrid:ApiKey"];
|
|
||||||
return new SendGridClient(apiKey);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Background Services
|
// Background Services
|
||||||
builder.Services.AddHostedService<TrialExpirationService>();
|
builder.Services.AddHostedService<HistoryCleanupService>();
|
||||||
|
|
||||||
// Response Caching
|
// Monitoring Services
|
||||||
builder.Services.AddResponseCaching();
|
if (builder.Configuration.GetValue<bool>("ResourceMonitoring:Enabled", true))
|
||||||
builder.Services.AddMemoryCache();
|
{
|
||||||
|
builder.Services.AddHostedService<ResourceMonitoringService>();
|
||||||
|
}
|
||||||
|
|
||||||
builder.Services.AddRazorPages();
|
if (builder.Configuration.GetValue<bool>("MongoDbMonitoring:Enabled", true))
|
||||||
|
{
|
||||||
|
builder.Services.AddHostedService<MongoDbMonitoringService>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// CORS for API endpoints
|
||||||
|
builder.Services.AddCors(options =>
|
||||||
|
{
|
||||||
|
options.AddPolicy("AllowSpecificOrigins", policy =>
|
||||||
|
{
|
||||||
|
policy.WithOrigins("https://qrrapido.site", "https://www.qrrapido.site")
|
||||||
|
.AllowAnyHeader()
|
||||||
|
.AllowAnyMethod();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Health checks with custom implementations
|
||||||
|
builder.Services.AddScoped<MongoDbHealthCheck>();
|
||||||
|
builder.Services.AddScoped<SeqHealthCheck>();
|
||||||
|
builder.Services.AddScoped<ResourceHealthCheck>();
|
||||||
|
builder.Services.AddScoped<ExternalServicesHealthCheck>();
|
||||||
|
|
||||||
|
builder.Services.AddHealthChecks()
|
||||||
|
.AddCheck<MongoDbHealthCheck>("mongodb")
|
||||||
|
.AddCheck<SeqHealthCheck>("seq")
|
||||||
|
.AddCheck<ResourceHealthCheck>("resources")
|
||||||
|
.AddCheck<ExternalServicesHealthCheck>("external_services");
|
||||||
|
|
||||||
|
builder.Services.Configure<ForwardedHeadersOptions>(options =>
|
||||||
|
{
|
||||||
|
options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
|
||||||
|
options.KnownProxies.Clear();
|
||||||
|
options.KnownNetworks.Clear();
|
||||||
|
});
|
||||||
|
|
||||||
var app = builder.Build();
|
var app = builder.Build();
|
||||||
|
|
||||||
// 🔥 PRIMEIRA COISA APÓS BUILD - FORWARDED HEADERS + BASE URL OVERRIDE
|
|
||||||
app.UseForwardedHeaders();
|
app.UseForwardedHeaders();
|
||||||
|
|
||||||
// 🚨 FORÇA BASE URL HTTPS EM PRODUÇÃO
|
// Configure the HTTP request pipeline
|
||||||
if (!app.Environment.IsDevelopment())
|
|
||||||
{
|
|
||||||
app.Use(async (context, next) =>
|
|
||||||
{
|
|
||||||
// Força o contexto a pensar que está em HTTPS
|
|
||||||
context.Request.Scheme = "https";
|
|
||||||
|
|
||||||
// Override do Host se necessário
|
|
||||||
if (context.Request.Host.Host == "bcards.site")
|
|
||||||
{
|
|
||||||
context.Request.Host = new HostString("bcards.site", 443);
|
|
||||||
}
|
|
||||||
|
|
||||||
await next();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Configure the HTTP request pipeline.
|
|
||||||
if (!app.Environment.IsDevelopment())
|
if (!app.Environment.IsDevelopment())
|
||||||
{
|
{
|
||||||
app.UseExceptionHandler("/Home/Error");
|
app.UseExceptionHandler("/Home/Error");
|
||||||
@ -239,128 +240,65 @@ if (!app.Environment.IsDevelopment())
|
|||||||
}
|
}
|
||||||
|
|
||||||
app.UseHttpsRedirection();
|
app.UseHttpsRedirection();
|
||||||
|
|
||||||
app.UseStaticFiles();
|
app.UseStaticFiles();
|
||||||
|
|
||||||
|
// Language redirection middleware (before routing)
|
||||||
|
app.UseMiddleware<LanguageRedirectionMiddleware>();
|
||||||
|
|
||||||
app.UseRouting();
|
app.UseRouting();
|
||||||
|
|
||||||
|
// Localization middleware (after routing so route data is available)
|
||||||
app.UseRequestLocalization();
|
app.UseRequestLocalization();
|
||||||
|
|
||||||
|
app.UseCors("AllowSpecificOrigins");
|
||||||
|
|
||||||
app.UseAuthentication();
|
app.UseAuthentication();
|
||||||
app.UseAuthorization();
|
app.UseAuthorization();
|
||||||
|
|
||||||
// Add custom middleware
|
app.UseSession();
|
||||||
app.UseMiddleware<BCards.Web.Middleware.PlanLimitationMiddleware>();
|
|
||||||
app.UseMiddleware<BCards.Web.Middleware.PageStatusMiddleware>();
|
|
||||||
app.UseMiddleware<BCards.Web.Middleware.PreviewTokenMiddleware>();
|
|
||||||
app.UseMiddleware<ModerationAuthMiddleware>();
|
|
||||||
|
|
||||||
// 🔥 DEBUG MIDDLEWARE MELHORADO
|
// Custom middleware
|
||||||
app.Use(async (context, next) =>
|
app.UseMiddleware<LastLoginUpdateMiddleware>();
|
||||||
{
|
|
||||||
// Debug geral
|
|
||||||
Console.WriteLine($"=== REQUEST DEBUG ===");
|
|
||||||
Console.WriteLine($"Path: {context.Request.Path}");
|
|
||||||
Console.WriteLine($"Query: {context.Request.QueryString}");
|
|
||||||
Console.WriteLine($"Method: {context.Request.Method}");
|
|
||||||
Console.WriteLine($"Scheme: {context.Request.Scheme}");
|
|
||||||
Console.WriteLine($"IsHttps: {context.Request.IsHttps}");
|
|
||||||
Console.WriteLine($"Host: {context.Request.Host}");
|
|
||||||
|
|
||||||
// Debug específico para Microsoft signin
|
// Health check endpoint
|
||||||
if (context.Request.Path.StartsWithSegments("/signin-microsoft"))
|
app.MapHealthChecks("/health");
|
||||||
{
|
|
||||||
var logger = context.RequestServices.GetRequiredService<ILogger<Program>>();
|
|
||||||
logger.LogWarning($"=== SIGNIN-MICROSOFT CALLBACK DEBUG ===");
|
|
||||||
logger.LogWarning($"Path: {context.Request.Path}");
|
|
||||||
logger.LogWarning($"Query: {context.Request.QueryString}");
|
|
||||||
logger.LogWarning($"Method: {context.Request.Method}");
|
|
||||||
logger.LogWarning($"Scheme: {context.Request.Scheme}");
|
|
||||||
logger.LogWarning($"IsHttps: {context.Request.IsHttps}");
|
|
||||||
logger.LogWarning($"Host: {context.Request.Host}");
|
|
||||||
logger.LogWarning($"X-Forwarded-Proto: {context.Request.Headers["X-Forwarded-Proto"]}");
|
|
||||||
logger.LogWarning($"X-Forwarded-For: {context.Request.Headers["X-Forwarded-For"]}");
|
|
||||||
logger.LogWarning($"All Headers:");
|
|
||||||
foreach (var header in context.Request.Headers)
|
|
||||||
{
|
|
||||||
logger.LogWarning($" {header.Key}: {header.Value}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
await next();
|
|
||||||
});
|
|
||||||
|
|
||||||
app.UseResponseCaching();
|
|
||||||
|
|
||||||
// Rotas específicas primeiro
|
|
||||||
app.MapControllerRoute(
|
|
||||||
name: "userpage-preview-path",
|
|
||||||
pattern: "page/preview/{category}/{slug}",
|
|
||||||
defaults: new { controller = "UserPage", action = "Preview" },
|
|
||||||
constraints: new { category = @"^[a-zA-Z-]+$", slug = @"^[a-z0-9-]+$" });
|
|
||||||
|
|
||||||
app.MapControllerRoute(
|
|
||||||
name: "userpage-click",
|
|
||||||
pattern: "page/click/{pageId}",
|
|
||||||
defaults: new { controller = "UserPage", action = "RecordClick" });
|
|
||||||
|
|
||||||
app.MapControllerRoute(
|
|
||||||
name: "moderation",
|
|
||||||
pattern: "moderation/{action=Dashboard}/{id?}",
|
|
||||||
defaults: new { controller = "Moderation" });
|
|
||||||
|
|
||||||
// Rota principal que vai pegar ?preview=token
|
|
||||||
//app.MapControllerRoute(
|
//app.MapControllerRoute(
|
||||||
// name: "userpage",
|
// name: "auth",
|
||||||
// pattern: "page/{category}/{slug}",
|
// pattern: "signin-{provider}",
|
||||||
// defaults: new { controller = "UserPage", action = "Display" },
|
// defaults: new { controller = "Account", action = "ExternalLoginCallback" });
|
||||||
// constraints: new { category = @"^[a-zA-Z-]+$", slug = @"^[a-z0-9-]+$" });
|
|
||||||
|
|
||||||
// 🔥 NOVA ROTA: LivePageController para páginas otimizadas de SEO
|
//app.MapControllerRoute(
|
||||||
|
// name: "account",
|
||||||
|
// pattern: "Account/{action}",
|
||||||
|
// defaults: new { controller = "Account" });
|
||||||
|
|
||||||
|
// Language routes (must be first)
|
||||||
app.MapControllerRoute(
|
app.MapControllerRoute(
|
||||||
name: "livepage",
|
name: "localized",
|
||||||
pattern: "page/{category}/{slug}",
|
pattern: "{culture:regex(^(pt-BR|es-PY|es)$)}/{controller=Home}/{action=Index}/{id?}");
|
||||||
defaults: new { controller = "LivePage", action = "Display" },
|
|
||||||
constraints: new
|
|
||||||
{
|
|
||||||
category = @"^[a-zA-Z0-9\-\u00C0-\u017F]+$", // ← Aceita acentos
|
|
||||||
slug = @"^[a-z0-9-]+$"
|
|
||||||
});
|
|
||||||
|
|
||||||
// Rota padrão por último
|
// API routes
|
||||||
|
app.MapControllerRoute(
|
||||||
|
name: "api",
|
||||||
|
pattern: "api/{controller}/{action=Index}/{id?}");
|
||||||
|
|
||||||
|
// Default fallback route (for development/testing without culture)
|
||||||
app.MapControllerRoute(
|
app.MapControllerRoute(
|
||||||
name: "default",
|
name: "default",
|
||||||
pattern: "{controller=Home}/{action=Index}/{id?}");
|
pattern: "{controller=Home}/{action=Index}/{id?}");
|
||||||
|
|
||||||
// Initialize default data
|
try
|
||||||
using (var scope = app.Services.CreateScope())
|
|
||||||
{
|
{
|
||||||
var themeService = scope.ServiceProvider.GetRequiredService<IThemeService>();
|
Log.Information("Starting QRRapido application");
|
||||||
var categoryService = scope.ServiceProvider.GetRequiredService<ICategoryService>();
|
app.Run();
|
||||||
|
}
|
||||||
try
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
// Initialize themes
|
Log.Fatal(ex, "QRRapido application terminated unexpectedly");
|
||||||
var existingThemes = await themeService.GetAvailableThemesAsync();
|
}
|
||||||
if (!existingThemes.Any())
|
finally
|
||||||
{
|
{
|
||||||
await themeService.InitializeDefaultThemesAsync();
|
Log.CloseAndFlush();
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize categories
|
|
||||||
var existingCategories = await categoryService.GetAllCategoriesAsync();
|
|
||||||
if (!existingCategories.Any())
|
|
||||||
{
|
|
||||||
await categoryService.InitializeDefaultCategoriesAsync();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
var logger = scope.ServiceProvider.GetRequiredService<ILogger<Program>>();
|
|
||||||
logger.LogError(ex, "Error initializing default data");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
app.Run();
|
|
||||||
|
|
||||||
// Make Program accessible for integration tests
|
|
||||||
public partial class Program { }
|
|
||||||
Loading…
Reference in New Issue
Block a user