using System; using System.Collections.Generic; using System.IO; using System.Linq; using Hangfire; using Hangfire.PostgreSql; using Kurs.Languages; using Kurs.MailQueue; using Kurs.Notifications.Application; using Kurs.Platform.Classrooms; using Kurs.Platform.EntityFrameworkCore; using Kurs.Platform.Extensions; using Kurs.Platform.FileManagement; using Kurs.Platform.Identity; using Kurs.Platform.Localization; using Kurs.Settings; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Cors; using Microsoft.AspNetCore.Extensions.DependencyInjection; using Microsoft.AspNetCore.Identity; using Microsoft.Extensions.Caching.StackExchangeRedis; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Hosting; using Microsoft.OpenApi.Models; using OpenIddict.Server.AspNetCore; using OpenIddict.Validation.AspNetCore; using Volo.Abp; using Volo.Abp.Account.Web; using Volo.Abp.AspNetCore.Auditing; using Volo.Abp.AspNetCore.ExceptionHandling; using Volo.Abp.AspNetCore.MultiTenancy; using Volo.Abp.AspNetCore.Mvc; using Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations; using Volo.Abp.AspNetCore.Mvc.UI.Bundling; using Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic; using Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Bundling; using Volo.Abp.AspNetCore.Serilog; using Volo.Abp.Autofac; using Volo.Abp.BackgroundWorkers.Hangfire; using Volo.Abp.BlobStoring; using Volo.Abp.BlobStoring.FileSystem; using Volo.Abp.Caching; using Volo.Abp.Hangfire; using Volo.Abp.Identity; using Volo.Abp.Modularity; using Volo.Abp.Security.Claims; using Volo.Abp.Swashbuckle; using Volo.Abp.UI.Navigation.Urls; using Volo.Abp.VirtualFileSystem; using static Kurs.Platform.PlatformConsts; using static Kurs.Settings.SettingsConsts; namespace Kurs.Platform; [DependsOn( typeof(PlatformHttpApiModule), typeof(AbpAutofacModule), typeof(AbpAspNetCoreMultiTenancyModule), typeof(PlatformApplicationModule), typeof(PlatformEntityFrameworkCoreModule), typeof(AbpAspNetCoreMvcUiBasicThemeModule), typeof(AbpAccountWebOpenIddictModule), typeof(AbpAspNetCoreSerilogModule), typeof(AbpSwashbuckleModule), typeof(AbpBackgroundWorkersHangfireModule) )] public class PlatformHttpApiHostModule : AbpModule { public override void PreConfigureServices(ServiceConfigurationContext context) { PreConfigure(builder => { builder.AddServer(server => { server.SetAccessTokenLifetime(TimeSpan.FromMinutes(60)); server.SetRefreshTokenLifetime(TimeSpan.FromMinutes(90)); }); builder.AddValidation(options => { options.AddAudiences(PlatformConsts.AppName); options.UseLocalServer(); options.UseAspNetCore(); }); }); PreConfigure(builder => { builder.AddClaimsPrincipalFactory(); builder.AddSignInManager(); }); context.Services.Replace( ServiceDescriptor.Transient()); context.Services.AddTransient(); } public override void ConfigureServices(ServiceConfigurationContext context) { var configuration = context.Services.GetConfiguration(); //Tenant bazında lokalizasyon ayarları için //TenantLocalization Middleware kaydı context.Services.AddTransient(); context.Services.AddTransient(); ConfigureAuthentication(context); ConfigureBundles(); ConfigureUrls(configuration); ConfigureConventionalControllers(); //Localization'ı veritabanından kullandıgımız icin bir json resource kullanmıyoruz //Dolayısıyla şimdilik ihtiyacımız yok ama ileride başka bir sebepten kullanabiliriz diye silmedik //ConfigureVirtualFileSystem(context); ConfigureCors(context, configuration); ConfigureSwaggerServices(context, configuration); ConfigureIdentity(configuration); ConfigureCache(); ConfigureHangfire(context, configuration); ConfigureBlobStoring(configuration); ConfigureAuditing(); context.Services.AddSignalR(); Configure(options => { options.Map(AppErrorCodes.NoAuth, System.Net.HttpStatusCode.Unauthorized); }); Configure(options => { options.DisableTransportSecurityRequirement = true; }); Configure(options => { options.Contributors.AddIfNotContains(new PlatformApplicationConfigurationContributor()); }); } private void ConfigureAuthentication(ServiceConfigurationContext context) { context.Services.ForwardIdentityAuthenticationForBearer(OpenIddictValidationAspNetCoreDefaults.AuthenticationScheme); context.Services.Configure(options => { options.IsDynamicClaimsEnabled = true; }); } private void ConfigureBundles() { Configure(options => { options.StyleBundles.Configure( BasicThemeBundles.Styles.Global, bundle => { bundle.AddFiles("/global-styles.css"); } ); }); } private void ConfigureUrls(IConfiguration configuration) { Configure(options => { options.RedirectAllowedUrls.AddRange(configuration["App:RedirectAllowedUrls"]?.Split(',') ?? Array.Empty()); options.Applications[PlatformConsts.React].RootUrl = configuration["App:ClientUrl"]; options.Applications[PlatformConsts.React].Urls[PlatformConsts.Urls.EmailConfirmation] = "account/confirm"; options.Applications[PlatformConsts.React].Urls[PlatformConsts.Urls.PasswordReset] = "account/reset-password"; options.Applications[PlatformConsts.React].Urls[PlatformConsts.Urls.UserDetail] = "account/{0}"; //options.Applications["MVC"].RootUrl = configuration["App:SelfUrl"]; //options.Applications["MVC"].Urls[PlatformConsts.Urls.EmailConfirmation] = "Account/Confirm"; //options.Applications["MVC"].Urls[PlatformConsts.Urls.TwoFactor] = "Account/TwoFactor"; //options.Applications["MVC"].Urls[PlatformConsts.Urls.Login] = "Account/Login"; //options.Applications["MVC"].Urls[PlatformConsts.Urls.UserDetail] = "Identity/Users/Detail"; }); } private void ConfigureConventionalControllers() { Configure(options => { options.ConventionalControllers.Create(typeof(PlatformApplicationModule).Assembly, opts => { opts.TypePredicate = t => t.Namespace == "Kurs.Platform.ListForms.Administration"; opts.RootPath = "admin"; }); options.ConventionalControllers.Create(typeof(PlatformApplicationModule).Assembly, opts => { opts.TypePredicate = t => t.Namespace != "Kurs.Platform.ListForms.Administration"; opts.RootPath = "app"; }); options.ConventionalControllers.Create(typeof(LanguagesApplicationModule).Assembly); options.ConventionalControllers.Create(typeof(SettingsApplicationModule).Assembly); options.ConventionalControllers.Create(typeof(KursMailQueueModule).Assembly); options.ConventionalControllers.Create(typeof(NotificationApplicationModule).Assembly); options.ChangeControllerModelApiExplorerGroupName = false; options.ConventionalControllers.FormBodyBindingIgnoredTypes.Add(typeof(PlatformUpdateProfileDto)); options.ConventionalControllers.FormBodyBindingIgnoredTypes.Add(typeof(UploadFileDto)); }); } private void ConfigureVirtualFileSystem(ServiceConfigurationContext context) { var hostingEnvironment = context.Services.GetHostingEnvironment(); if (hostingEnvironment.IsDevelopment()) { Configure(options => { options.FileSets.ReplaceEmbeddedByPhysical( Path.Combine(hostingEnvironment.ContentRootPath, $"..{Path.DirectorySeparatorChar}Kurs.Platform.Domain.Shared")); options.FileSets.ReplaceEmbeddedByPhysical( Path.Combine(hostingEnvironment.ContentRootPath, $"..{Path.DirectorySeparatorChar}Kurs.Platform.Domain")); options.FileSets.ReplaceEmbeddedByPhysical( Path.Combine(hostingEnvironment.ContentRootPath, $"..{Path.DirectorySeparatorChar}Kurs.Platform.Application.Contracts")); options.FileSets.ReplaceEmbeddedByPhysical( Path.Combine(hostingEnvironment.ContentRootPath, $"..{Path.DirectorySeparatorChar}Kurs.Platform.Application")); options.FileSets.ReplaceEmbeddedByPhysical( Path.Combine(hostingEnvironment.ContentRootPath, $"..{Path.DirectorySeparatorChar}Kurs.MailQueue")); }); } } private void ConfigureCors(ServiceConfigurationContext context, IConfiguration configuration) { context.Services.AddCors(options => { options.AddDefaultPolicy(builder => { builder .WithOrigins(configuration["App:CorsOrigins"]? .Split(",", StringSplitOptions.RemoveEmptyEntries) .Select(o => o.RemovePostFix("/")) .ToArray() ?? Array.Empty()) .WithAbpExposedHeaders() .WithExposedHeaders(["X-Correlation-Id"]) .SetIsOriginAllowedToAllowWildcardSubdomains() .AllowAnyHeader() .AllowAnyMethod() .AllowCredentials(); }); }); } private void ConfigureSwaggerServices(ServiceConfigurationContext context, IConfiguration configuration) { context.Services.AddAbpSwaggerGenWithOAuth( configuration["AuthServer:Authority"], new Dictionary { {"Platform", "Platform API"} }, options => { options.SwaggerDoc("v1", new OpenApiInfo { Title = "Platform API", Version = "v1" }); options.DocInclusionPredicate((docName, description) => true); options.CustomSchemaIds(type => type.FullName); }); } private void ConfigureIdentity(IConfiguration configuration) { //Veritabanından yonetildigi icin bunlar kapatildi //Configure(options => //{ // options.SignIn.RequireConfirmedEmail = true; // options.SignIn.RequireConfirmedAccount = true; // options.SignIn.RequireConfirmedPhoneNumber = false; // options.User.RequireUniqueEmail = true; // options.Lockout.AllowedForNewUsers = true; // options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(5); // options.Lockout.MaxFailedAccessAttempts = 5; // options.Password.RequiredLength = 6; // options.Password.RequiredUniqueChars = 0; // options.Password.RequireNonAlphanumeric = false; // options.Password.RequireLowercase = false; // options.Password.RequireUppercase = false; // options.Password.RequireDigit = false; //}); Configure(configuration.GetSection(PlatformConsts.AbpIdentity.GroupName)); } private void ConfigureCache() { Configure(options => { options.KeyPrefix = PlatformConsts.AppName; }); Configure(options => { }); } private void ConfigureHangfire(ServiceConfigurationContext context, IConfiguration configuration) { Configure(options => { options.ServerOptions = new BackgroundJobServerOptions() { Queues = ["default", "platform"] }; }); context.Services.AddHangfire(config => { switch (DefaultDatabaseProvider) { case DatabaseProvider.PostgreSql: config.UsePostgreSqlStorage(c => c.UseNpgsqlConnection(configuration.GetConnectionString(DefaultDatabaseProvider))); break; case DatabaseProvider.SqlServer: config.UseSqlServerStorage(configuration.GetConnectionString(DefaultDatabaseProvider)); break; default: throw new InvalidOperationException("Unsupported database provider configured for Hangfire."); } }); } private void ConfigureBlobStoring(IConfiguration configuration) { Configure(options => { options.Containers.ConfigureDefault(container => { container.UseFileSystem(fileSystem => { fileSystem.BasePath = configuration["App:CdnPath"]; }); }); }); } private void ConfigureAuditing() { Configure(options => { options.IgnoredUrls.Add("/api/app/list-form-customization"); }); } public override void OnApplicationInitialization(ApplicationInitializationContext context) { var app = context.GetApplicationBuilder(); var env = context.GetEnvironment(); if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseAbpRequestLocalization(); // Auth hataları MVC tarafından /Error sayfasına yönlendirilmesin diye bu kaldırıldı // if (!env.IsDevelopment()) // { // app.UseErrorPage(); // } app.UseCorrelationId(); app.MapAbpStaticAssets(); app.UseRouting(); app.UseCors(); app.UseAuthentication(); app.UseAbpOpenIddictValidation(); app.UseMiddleware(); if (PlatformConsts.IsMultiTenant) { app.UseMultiTenancy(); app.UseMiddleware(); } app.UseUnitOfWork(); app.UseDynamicClaims(); app.UseAuthorization(); app.UseSwagger(); app.UseAbpSwaggerUI(c => { c.SwaggerEndpoint("/swagger/v1/swagger.json", "Platform API"); var configuration = context.ServiceProvider.GetRequiredService(); c.OAuthClientId(configuration["AuthServer:SwaggerClientId"]); c.OAuthScopes("Platform"); }); app.UseAuditing(); app.UseAbpSerilogEnrichers(); if (env.IsDevelopment()) { app.UseHangfireDashboard(); } else { app.UseHangfireDashboard("/hangfire", new DashboardOptions { AsyncAuthorization = [new AbpHangfireAuthorizationFilter()] }); } app.UseEndpoints(endpoints => { endpoints.MapHub("/classroomhub"); }); app.UseConfiguredEndpoints(); } }