992 lines
49 KiB
C#
992 lines
49 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Globalization;
|
|
using System.IdentityModel.Tokens.Jwt;
|
|
using System.IO;
|
|
using System.Net;
|
|
using System.Net.Http;
|
|
using System.Security.Claims;
|
|
using System.Text.Json;
|
|
using System.Text.Json.Serialization;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using Aeroflot.Common.ApiWrappers;
|
|
using Aeroflot.Common2.ApiWrapper.Aeroflot;
|
|
using Aeroflot.Common2.ApiWrapper.Aeroflot.FallbackService;
|
|
using Aeroflot.Common2.ApiWrapper.Aeroflot.Proxies;
|
|
using Aeroflot.Common2.DataAccess.S3;
|
|
using Aeroflot.Common2.Extensions;
|
|
using Aeroflot.Common2.Observability.AspNetCore;
|
|
using Aeroflot.Flights.BL;
|
|
using Aeroflot.Flights.BL.Helpers;
|
|
using Aeroflot.Flights.BL.Models;
|
|
using Aeroflot.Flights.BL.Models.FlightFilter;
|
|
using Aeroflot.Flights.DataSpace;
|
|
using Aeroflot.Flights.Interfaces.Models;
|
|
using Aeroflot.Flights.WebApi;
|
|
using Aeroflot.Flights.WebApi.Models;
|
|
using Aeroflot.Flights.WebApi.Models.Onlineboard.ApiV1;
|
|
using Aeroflot.Flights.WebApi.Providers;
|
|
//using Aeroflot.Flights.WebApi.SignalR;
|
|
using Aeroflot.Security2;
|
|
using Aeroflot.Security2.DataAccess;
|
|
using Aeroflot.Security2.DataSpace;
|
|
using Aeroflot.Security2.Entities;
|
|
using Aeroflot.Security2.Entities.DataSpace;
|
|
using Aeroflot.Security2.Services.EmailService;
|
|
using Amazon.Runtime;
|
|
using Amazon.S3;
|
|
using Microsoft.AspNetCore.Authentication.Cookies;
|
|
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
|
using Microsoft.AspNetCore.Authorization;
|
|
using Microsoft.AspNetCore.Builder;
|
|
using Microsoft.AspNetCore.DataProtection;
|
|
using Microsoft.AspNetCore.Hosting;
|
|
using Microsoft.AspNetCore.Http;
|
|
using Microsoft.AspNetCore.Http.Features;
|
|
using Microsoft.AspNetCore.HttpOverrides;
|
|
using Microsoft.AspNetCore.Identity;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
|
//using Microsoft.AspNetCore.SignalR;
|
|
using Microsoft.AspNetCore.SpaServices.AngularCli;
|
|
using Microsoft.Extensions.Configuration;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
using Microsoft.Extensions.DependencyInjection.Extensions;
|
|
using Microsoft.Extensions.Hosting;
|
|
using Microsoft.Extensions.Logging;
|
|
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
|
|
using Microsoft.OpenApi.Models;
|
|
using Newtonsoft.Json.Serialization;
|
|
using Prometheus;
|
|
using Serilog;
|
|
|
|
namespace Aeroflot.Flights.Web
|
|
{
|
|
public class Startup
|
|
{
|
|
private const string UserAgent = "Aeroflot.Flights / 1.0.001"; //"Aeroflot.Passbook / 1.7.013";
|
|
//private IHubContext<FlightHub> hubContext;
|
|
|
|
public Startup(IWebHostEnvironment env)
|
|
{
|
|
Environment = env;
|
|
|
|
var builder = new ConfigurationBuilder()
|
|
.SetBasePath(env.ContentRootPath)
|
|
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
|
|
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
|
|
.AddEnvironmentVariables();
|
|
Configuration = builder.Build();
|
|
}
|
|
|
|
public IWebHostEnvironment Environment { get; }
|
|
|
|
public IConfiguration Configuration { get; }
|
|
|
|
public class AuthMessageHandler : DelegatingHandler
|
|
{
|
|
public AuthMessageHandler()
|
|
{
|
|
InnerHandler = new HttpClientHandler();
|
|
}
|
|
|
|
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
|
|
{
|
|
request.Headers.Add("User-Agent", UserAgent);
|
|
return base.SendAsync(request, cancellationToken);
|
|
}
|
|
}
|
|
|
|
public void ConfigureServices(IServiceCollection services)
|
|
{
|
|
var keysFolder = System.IO.Path.Combine(Environment.ContentRootPath, "App_Data");
|
|
services.AddDataProtection()
|
|
.SetApplicationName("Flights")
|
|
.PersistKeysToFileSystem(new DirectoryInfo(keysFolder))
|
|
.SetDefaultKeyLifetime(TimeSpan.FromDays(36500)) // 100 years
|
|
.DisableAutomaticKeyGeneration();
|
|
|
|
//IdentityModelEventSource.ShowPII = true;
|
|
services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
|
|
|
|
services.AddSpaStaticFiles(config =>
|
|
{
|
|
config.RootPath = "ClientApp/dist";
|
|
});
|
|
|
|
//var apiAssembly = typeof(WebApi.Controllers.FlightsController).Assembly;
|
|
services.AddMvc()
|
|
.AddNewtonsoftJson(opt =>
|
|
{
|
|
opt.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
|
|
opt.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
|
|
opt.SerializerSettings.NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore;
|
|
opt.SerializerSettings.Converters.Add(new Newtonsoft.Json.Converters.StringEnumConverter());
|
|
opt.AllowInputFormatterExceptionMessages = true;
|
|
})
|
|
.AddXmlSerializerFormatters()
|
|
.AddXmlDataContractSerializerFormatters();
|
|
services.AddSession();
|
|
services.AddResponseCaching();
|
|
services.AddControllers(options =>
|
|
{
|
|
options.CacheProfiles.Add(
|
|
"DefaultBoard",
|
|
new CacheProfile()
|
|
{
|
|
Duration = int.TryParse(Configuration["Options:Cache:DefaultBoard"], out int cacheBoardSeconds) ? cacheBoardSeconds : 60,
|
|
VaryByQueryKeys = new[] { "*" },
|
|
});
|
|
options.CacheProfiles.Add(
|
|
"DefaultDictionary",
|
|
new CacheProfile()
|
|
{
|
|
Duration = int.TryParse(Configuration["Options:Cache:DefaultDictionary"], out int cacheDictionarySeconds) ? cacheDictionarySeconds : 3600,
|
|
VaryByQueryKeys = new[] { "*" },
|
|
});
|
|
options.CacheProfiles.Add(
|
|
"DefaultSchedule",
|
|
new CacheProfile()
|
|
{
|
|
Duration = int.TryParse(Configuration["Options:Cache:DefaultSchedule"], out int cacheScheduleSeconds) ? cacheScheduleSeconds : 600,
|
|
VaryByQueryKeys = new[] { "*" },
|
|
});
|
|
options.CacheProfiles.Add(
|
|
"DefaultDetails",
|
|
new CacheProfile()
|
|
{
|
|
Duration = int.TryParse(Configuration["Options:Cache:DefaultDetails"], out int cacheDetailsSeconds) ? cacheDetailsSeconds : 30,
|
|
VaryByQueryKeys = new[] { "*" },
|
|
});
|
|
options.CacheProfiles.Add(
|
|
"DefaultAirport",
|
|
new CacheProfile()
|
|
{
|
|
Duration = int.TryParse(Configuration["Options:Cache:DefaultAirport"], out int cacheAirportSeconds) ? cacheAirportSeconds : 600,
|
|
Location = ResponseCacheLocation.Any,
|
|
VaryByQueryKeys = new[] { "*" },
|
|
});
|
|
options.CacheProfiles.Add(
|
|
"Default1HourBasedOnQueryKeys",
|
|
new CacheProfile()
|
|
{
|
|
Duration = 3600,
|
|
VaryByQueryKeys = new[] { "*" },
|
|
});
|
|
options.CacheProfiles.Add(
|
|
"DefaultRequests",
|
|
new CacheProfile()
|
|
{
|
|
Duration = int.TryParse(Configuration["Options:Cache:DefaultRequest"], out int cacheRequestsSeconds) ? cacheRequestsSeconds : 600,
|
|
VaryByQueryKeys = new[] { "*" },
|
|
});
|
|
})
|
|
.AddXmlSerializerFormatters()
|
|
.AddXmlDataContractSerializerFormatters();
|
|
|
|
services.AddWebApi();
|
|
|
|
services.AddMemoryCache();
|
|
|
|
services.AddSwaggerGen(c =>
|
|
{
|
|
//c.TagActionsBy(tagSelector => tagSelector.);
|
|
c.CustomSchemaIds(type => type.FullName.ToString());
|
|
c.SwaggerDoc("v1", new OpenApiInfo { Title = "Aeroflot Flights", Version = "v1" });
|
|
c.AddSecurityDefinition(
|
|
"Bearer",
|
|
new OpenApiSecurityScheme
|
|
{
|
|
In = ParameterLocation.Header,
|
|
Description = "Please enter JWT with Bearer into field",
|
|
Name = "Authorization",
|
|
Type = SecuritySchemeType.ApiKey,
|
|
});
|
|
c.AddSecurityRequirement(new OpenApiSecurityRequirement()
|
|
{
|
|
{
|
|
new OpenApiSecurityScheme
|
|
{
|
|
Reference = new OpenApiReference
|
|
{
|
|
Type = ReferenceType.SecurityScheme,
|
|
Id = "Bearer",
|
|
},
|
|
Scheme = "oauth2",
|
|
Name = "Bearer",
|
|
In = ParameterLocation.Header,
|
|
},
|
|
new List<string>()
|
|
},
|
|
});
|
|
c.DescribeAllParametersInCamelCase();
|
|
});
|
|
|
|
services.Configure<SwaggerBasicAuthConfig>(Configuration.GetSection("Swagger"));
|
|
services.AddEndpointsApiExplorer();
|
|
|
|
//ConfigureAuthService(services, Configuration);
|
|
|
|
#region //ToDo: refactor this
|
|
//var connectionString = Configuration.GetConnectionString("ConnectionString");
|
|
//services.AddDbContext<FlightDbContext>(
|
|
// builder =>
|
|
// builder.EnableSensitiveDataLogging().UseSqlServer(connectionString, options => options.EnableRetryOnFailure()),
|
|
// ServiceLifetime.Transient);
|
|
//services.AddDbContext<SecurityDbContext>(
|
|
// builder =>
|
|
// builder.UseSqlServer(connectionString, options => options.EnableRetryOnFailure()),
|
|
// ServiceLifetime.Transient);
|
|
|
|
var scheduleAppUri = new Uri(Configuration["Api:ScheduleAppUri"]);
|
|
var scheduleV2AppUri = new Uri(Configuration["Api:ScheduleV2AppUri"]);
|
|
|
|
Func<string, Uri> uriAccessor = key =>
|
|
{
|
|
switch (key)
|
|
{
|
|
case Common.ApiWrappers.Schedule.Schedule.AppUri:
|
|
return scheduleAppUri;
|
|
case Common.ApiWrappers.Schedule.Schedule.AppV2Uri:
|
|
return scheduleV2AppUri;
|
|
default:
|
|
throw new ArgumentOutOfRangeException();
|
|
}
|
|
};
|
|
services.AddSingleton(uriAccessor);
|
|
|
|
//services.AddSingleton(Options.Create<FlightsApiWrapperSettings>(new FlightsApiWrapperSettings { FlightsUri = new Uri(Configuration["Dictionary:FlightsApiAppUri"]) }));
|
|
#endregion
|
|
|
|
services.Configure<AflApiProviderOptions>(Configuration.GetSection("Options:RefreshableApiProvider"));
|
|
services.Configure<ApiWrapperProxyOptions>(Configuration.GetSection("Options:ApiWrapperProxy"));
|
|
|
|
services.Configure<DatesProviderOptions>(Configuration.GetSection("Options:DatesProviderOptions"));
|
|
services.Configure<AeroflotApiWrapperOptions>(Configuration.GetSection("Options:AeroflotApiWrapper"));
|
|
services.Configure<BL.Models.TransitionProviderOptions>(Configuration.GetSection("Options:TransitionProvider"));
|
|
services.Configure<BL.Models.LegServiceOptions>(Configuration.GetSection("Options:LegService"));
|
|
services.Configure<ConnectionsProviderOptions>(Configuration.GetSection("Options:ConnectionsProvider"));
|
|
services.Configure<ValidationOptions>(Configuration.GetSection("Options:Validation"));
|
|
services.Configure<WhiteListCarriersOptions>(Configuration.GetSection("Options:WhiteListCarriers"));
|
|
|
|
Enum.TryParse<FallbackServiceType>(Configuration.GetSection("Options:AeroflotFallbackOptions:ServiceType").Value, true, out FallbackServiceType serviceType);
|
|
|
|
var options = Configuration.GetAWSOptions("YandexAWS:AWS");
|
|
options.Credentials = new BasicAWSCredentials(Configuration.GetSection("YandexAWS:AWS:AccessKey").Value, Configuration.GetSection("YandexAWS:AWS:SecretKey").Value);
|
|
services.AddDefaultAWSOptions(options);
|
|
services.AddAWSService<IAmazonS3>();
|
|
services.AddSingleton<IS3BlobContainer<string>>(sp => ActivatorUtilities.CreateInstance<S3BlobContainer<string>>(sp, Configuration.GetSection("YandexAWS:Bucket").Value));
|
|
services.AddSingleton<IS3BlobContainer<byte[]>>(sp => ActivatorUtilities.CreateInstance<S3BlobContainer<byte[]>>(sp, Configuration.GetSection("YandexAWS:Bucket").Value));
|
|
|
|
services.AddOptions<FlightFilterProviderOptions>().Bind(Configuration.GetSection("Options:FlightFilter"));
|
|
services.AddOptions<HeadersOptions>().Bind(Configuration.GetSection("HeadersOptions"));
|
|
services.AddBlWeb(serviceType);
|
|
|
|
//add dataspace
|
|
services.AddFlightsClientGraphQL(Configuration["DataSpace:FlightsModelEndpoint"]);
|
|
services.AddSecurity2ClientGraphQL(Configuration["DataSpace:FlightsModelEndpoint"]);
|
|
|
|
//services.AddScoped<IdentityRepository, IdentityRepository>(); // (_ => new IdentityRepository((IAsyncGenericRepository)_.GetService(typeof(AsyncGenericRepository))));
|
|
//services.AddScoped<IPasswordHasher<User>, PasswordHasher<User>>();
|
|
//services.AddScoped<ILookupNormalizer, UpperInvariantLookupNormalizer>();
|
|
//services.AddScoped<IdentityErrorDescriber, IdentityErrorDescriber>();
|
|
//services.AddScoped<UserManager, UserManager>();
|
|
services.AddScoped<IIdentityRepository, IdentityRepository>();
|
|
services.AddScoped<ISearchFlightParamsBinder, SearchFlightParamsBinder>();
|
|
|
|
services.AddAeroflotIdentityCore<User>(o =>
|
|
{
|
|
o.User.RequireUniqueEmail = true;
|
|
o.User.AllowedUserNameCharacters = "абвгдеёжзийклмнопрстуфхцчшщъыьэюяАБВГДЕЁЖЗКИЙКЛМНОПРСТУФЧЦЧШЩЪЫЬЭЮЯ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
|
o.Lockout.MaxFailedAccessAttempts = 7;
|
|
})
|
|
.AddDefaultTokenProviders();
|
|
|
|
services.AddDefaultPasswordValidators<User>();
|
|
|
|
services.TryAddScoped<ISecurityStampValidator, SecurityStampValidator<Security2.Entities.User>>();
|
|
|
|
var configEws = Configuration.GetSection("EwsServiceOptions");
|
|
var ewsOptions = new EWSOptions()
|
|
{
|
|
AsmxUri = configEws.GetValue<string>("EwsAsmxUri"),
|
|
Password = configEws.GetValue<string>("EwsPassword"),
|
|
Username = configEws.GetValue<string>("EwsUserName"),
|
|
};
|
|
var configEmail = Configuration.GetSection("EmailOptions");
|
|
services.AddEWSEmailService(new EmailOptions()
|
|
{
|
|
AppName = configEmail.GetValue<string>("AppName"),
|
|
AppUrl = configEmail.GetValue<string>("AppUrl"),
|
|
InvitationUrl = configEmail.GetValue<string>("InvitationUrl"),
|
|
EWSOptions = ewsOptions,
|
|
});
|
|
services.TryAddScoped<IUserConfirmation<Security2.Entities.User>, DefaultUserConfirmation<Security2.Entities.User>>();
|
|
services.TryAddScoped<SignInManager<Security2.Entities.User>>();
|
|
|
|
services.Configure<FormOptions>(x =>
|
|
{
|
|
x.ValueLengthLimit = int.MaxValue;
|
|
x.MultipartBodyLengthLimit = int.MaxValue;
|
|
});
|
|
|
|
services.AddAuthentication(options =>
|
|
{
|
|
options.DefaultScheme = IdentityConstants.ApplicationScheme;
|
|
options.DefaultSignInScheme = IdentityConstants.ExternalScheme;
|
|
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
|
|
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
|
|
})
|
|
.AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, options =>
|
|
{
|
|
options.Authority = Configuration["Identity:AuthorityUri"];
|
|
options.Audience = Configuration["Identity:Audience"];
|
|
options.RequireHttpsMetadata = false;
|
|
options.BackchannelHttpHandler = new AuthMessageHandler();
|
|
})
|
|
.AddIdentityCookies(o =>
|
|
{
|
|
if (Environment.IsDevelopment())
|
|
{
|
|
o.ApplicationCookie.Configure(options =>
|
|
{
|
|
options.Cookie.HttpOnly = true;
|
|
options.Cookie.SameSite = SameSiteMode.None;
|
|
options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
|
|
});
|
|
o.ExternalCookie.Configure(options =>
|
|
{
|
|
options.Cookie.HttpOnly = true;
|
|
options.Cookie.SameSite = SameSiteMode.None;
|
|
options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
|
|
});
|
|
}
|
|
});
|
|
|
|
services.AddAuthorization(options =>
|
|
{
|
|
options.DefaultPolicy = new AuthorizationPolicyBuilder()
|
|
.RequireAuthenticatedUser()
|
|
.Build();
|
|
|
|
options.AddPolicy("policyjwt", policy =>
|
|
{
|
|
policy.AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme)
|
|
.RequireAuthenticatedUser();
|
|
});
|
|
|
|
options.AddPolicy("policycookie", policy =>
|
|
{
|
|
policy.AddAuthenticationSchemes(IdentityConstants.ApplicationScheme)
|
|
.RequireAuthenticatedUser();
|
|
});
|
|
});
|
|
|
|
services.AddHealthChecks();
|
|
|
|
services.AddCors(options =>
|
|
{
|
|
options.AddPolicy(
|
|
"Aeroflot",
|
|
builder =>
|
|
{
|
|
builder
|
|
.WithOrigins("http://*.aeroflot.ru", "https://*.aeroflot.ru", "http://aeroflot.baccasoft.ru", "https://aeroflot.baccasoft.ru", "http://*.test.aeroflot.ru", "https://*.test.aeroflot.ru")
|
|
.AllowAnyMethod()
|
|
.AllowAnyHeader()
|
|
.SetIsOriginAllowedToAllowWildcardSubdomains();
|
|
});
|
|
|
|
options.AddPolicy(
|
|
"AllowAnyHeader",
|
|
builder =>
|
|
{
|
|
builder
|
|
.AllowAnyOrigin()
|
|
.AllowAnyHeader()
|
|
.AllowAnyMethod();
|
|
});
|
|
});
|
|
|
|
//services.AddTransient<IFlightHubClient>(c => new FlightHubClient(hubContext));
|
|
//services.AddSignalR();
|
|
|
|
services.AddMvc()
|
|
.AddRazorPagesOptions(options =>
|
|
{
|
|
options.Conventions.AddPageRoute("/Robots", "/robots.txt");
|
|
options.Conventions.AddPageRoute("/Sitemap", "/sitemap.xml");
|
|
});
|
|
|
|
services.Configure<ForwardedHeadersOptions>(options =>
|
|
{
|
|
options.ForwardLimit = 3;
|
|
|
|
foreach (var ip in Configuration.GetSection("IpSettings").Get<List<IpOptions>>())
|
|
{
|
|
options.KnownNetworks.Add(new Microsoft.AspNetCore.HttpOverrides.IPNetwork(IPAddress.Parse(ip.Ip), ip.Mask));
|
|
}
|
|
|
|
options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
|
|
});
|
|
|
|
services.AddOpenTelemetryAspNetCore(Configuration["OpenTelemetry:ServiceName"], Configuration["OpenTelemetry:ServiceNamespace"], Configuration["OpenTelemetry:OtlpExporterEndpoint"]);
|
|
|
|
services.Configure<Microsoft.AspNetCore.Http.Json.JsonOptions>(o =>
|
|
{
|
|
o.SerializerOptions.Converters.Add(new JsonStringEnumConverter());
|
|
o.SerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
|
|
// DataSpace ids are 64 bit and need to be strings in Json
|
|
// ints in Json has only about 53bit precision
|
|
o.SerializerOptions.NumberHandling = JsonNumberHandling.WriteAsString | JsonNumberHandling.AllowReadingFromString;
|
|
o.SerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull;
|
|
});
|
|
}
|
|
|
|
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
|
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory logger)
|
|
{
|
|
app.UseForwardedHeaders();
|
|
|
|
if (env.IsDevelopment())
|
|
{
|
|
app.UseDeveloperExceptionPage();
|
|
app.UseBrowserLink();
|
|
}
|
|
|
|
app.UseHealthChecks("/healthy");
|
|
|
|
app.UseResponseCaching();
|
|
|
|
app.UseStaticFiles();
|
|
|
|
//if (!env.IsDevelopment())
|
|
//{
|
|
// app.UseSpaStaticFiles();
|
|
//}
|
|
app.UseSpaStaticFiles();
|
|
|
|
app.Use(async (context, next) =>
|
|
{
|
|
context.Request.EnableBuffering();
|
|
|
|
//var hubContext = context.RequestServices
|
|
// .GetRequiredService<IHubContext<FlightHub>>();
|
|
|
|
//this.hubContext = hubContext;
|
|
|
|
await next.Invoke();
|
|
});
|
|
|
|
app.UseHttpsRedirection();
|
|
|
|
app.UseRouting();
|
|
|
|
app.UseCors("Aeroflot");
|
|
|
|
app.UseHttpMetrics();
|
|
app.UseAuthentication();
|
|
app.UseAuthorization();
|
|
app.UseSession();
|
|
|
|
app.UseSerilogRequestLogging();
|
|
|
|
app.UseEndpoints(endpoints =>
|
|
{
|
|
endpoints.MapGet(
|
|
"api/v{version}/{lang}/airports", (
|
|
[FromServices] WebApi.Controllers.Api.AirportController controller,
|
|
HttpContext httpContext,
|
|
[FromRoute] double version,
|
|
[FromRoute] CaseInsensitive<Lang> lang) =>
|
|
controller.GetAirports(httpContext, version, lang.Value, "json")).Produces<WebApi.Models.Response<List<AirportModel>>>(StatusCodes.Status200OK)
|
|
.CacheOutput("DefaultAirport").WithTags("Airports").WithSummary("Get Airports");
|
|
|
|
endpoints.MapGet(
|
|
"api/v{version}/{lang}/airports.{format}", (
|
|
[FromServices] WebApi.Controllers.Api.AirportController controller,
|
|
HttpContext httpContext,
|
|
[FromRoute] double version,
|
|
[FromRoute] CaseInsensitive<Lang> lang,
|
|
[FromRoute] string format) =>
|
|
controller.GetAirports(httpContext, version, lang.Value, format)).Produces<WebApi.Models.Response<List<AirportModel>>>(StatusCodes.Status200OK)
|
|
.CacheOutput("DefaultAirport").WithTags("Airports").WithSummary("Get Airports");
|
|
|
|
endpoints.MapGet(
|
|
"api/v{version}/{lang}/airports/pairs", (
|
|
[FromServices] WebApi.Controllers.Api.AirportController controller,
|
|
HttpContext httpContext,
|
|
[FromRoute] double version,
|
|
[FromRoute] CaseInsensitive<Lang> lang) =>
|
|
controller.GetAirportPairs(httpContext, version, lang.Value)).Produces<WebApi.Models.Response<WrapperAirlineProfileRS>>(StatusCodes.Status200OK)
|
|
.CacheOutput("DefaultAirport").WithTags("Airports").WithSummary("Get Airports");
|
|
|
|
endpoints.MapGet(
|
|
"/api/AppSettings",
|
|
([FromServices] WebApi.Controllers.App.AppSettingsController controller) =>
|
|
controller.Get()).Produces<string>(StatusCodes.Status200OK)
|
|
.WithTags("AppSettings").WithSummary("Get App settings");
|
|
|
|
endpoints.MapPost(
|
|
"/api/Meal/checkspecial",
|
|
([FromServices] WebApi.Controllers.App.MealController controller,
|
|
[FromBody] MealApiRequestModel model) =>
|
|
controller.CheckMealAsync(model)).Produces<bool>(StatusCodes.Status200OK)
|
|
.WithTags("Meal").WithSummary("Get meal information");
|
|
|
|
endpoints.MapGet(
|
|
"api/v{version}/{language}/delays/statistics", (
|
|
[FromServices] WebApi.Controllers.Api.DelaysController controller,
|
|
HttpContext httpContext,
|
|
ClaimsPrincipal user,
|
|
[FromRoute] double version,
|
|
[FromRoute] string language) =>
|
|
controller.GetDelayStatistics(httpContext, user, version, language)).Produces<string>(StatusCodes.Status200OK)
|
|
.WithTags("Delays").WithSummary("Get delays statistics");
|
|
|
|
endpoints.MapGet(
|
|
"api/Healthcheck", (
|
|
[FromServices] WebApi.Controllers.App.HealthcheckController controller,
|
|
HttpContext httpContext,
|
|
ClaimsPrincipal user) =>
|
|
controller.Get()).Produces<string>(StatusCodes.Status200OK)
|
|
.WithTags("Healthcheck").WithSummary("Health check");
|
|
|
|
endpoints.MapGet(
|
|
"api/Dictionary/{version}/{dictionaryName}", (
|
|
[FromServices] WebApi.Controllers.App.DictionaryController controller,
|
|
HttpContext httpContext,
|
|
ClaimsPrincipal user,
|
|
string dictionaryName,
|
|
string version) =>
|
|
controller.GetData(dictionaryName, version)).Produces<string>(StatusCodes.Status200OK)
|
|
.CacheOutput("DefaultDictionary").WithTags("Dictionary").WithSummary("Get dictionaries");
|
|
|
|
endpoints.MapGet(
|
|
"api/Flights/{version}/{lang}/board", (
|
|
[FromServices] WebApi.Controllers.App.FlightsController controller,
|
|
HttpContext httpContext,
|
|
ClaimsPrincipal user,
|
|
[AsParameters] WebApi.Providers.SearchFlightParams searchParams,
|
|
string version,
|
|
string lang) =>
|
|
controller.GetOnlineBoard(searchParams, version, lang, httpContext))
|
|
.CacheOutput("DefaultBoard").WithTags("Flights").WithSummary("Get online board");
|
|
|
|
endpoints.MapGet(
|
|
"api/Flights/{version}/{lang}/schedule", (
|
|
[FromServices] WebApi.Controllers.App.FlightsController controller,
|
|
HttpContext httpContext,
|
|
ClaimsPrincipal user,
|
|
[AsParameters] WebApi.Providers.SearchFlightParams searchParams,
|
|
string version,
|
|
string lang) =>
|
|
controller.GetSchedule(searchParams, version, lang, httpContext))
|
|
.CacheOutput("DefaultSchedule").WithTags("Flights").WithSummary("Get schedule");
|
|
|
|
endpoints.MapGet(
|
|
"api/Flights/{version}/{lang}/schedule_pdf", (
|
|
[FromServices] WebApi.Controllers.App.FlightsController controller,
|
|
HttpContext httpContext,
|
|
ClaimsPrincipal user,
|
|
[AsParameters] WebApi.Providers.SearchFlightParams searchParams,
|
|
string version,
|
|
string lang) =>
|
|
controller.GetSchedulePdf(searchParams, version, lang, httpContext))
|
|
.CacheOutput("DefaultSchedule").WithTags("Flights").WithSummary("Get schedule PDF");
|
|
|
|
endpoints.MapGet(
|
|
"api/Flights/{version}/{lang}/get_partner", (
|
|
[FromServices] WebApi.Controllers.App.FlightsController controller,
|
|
HttpContext httpContext,
|
|
ClaimsPrincipal user,
|
|
[AsParameters] WebApi.Providers.SearchFlightParams searchParams,
|
|
string version,
|
|
string lang) =>
|
|
controller.GetPartner(searchParams, version, lang))
|
|
.WithTags("Flights").WithSummary("Get partner (obsolete)");
|
|
|
|
endpoints.MapGet(
|
|
"api/Flights/{version}/{lang}/actual", (
|
|
[FromServices] WebApi.Controllers.App.FlightsController controller,
|
|
HttpContext httpContext,
|
|
ClaimsPrincipal user,
|
|
[AsParameters] WebApi.Providers.SearchFlightParams searchParams,
|
|
string version,
|
|
string lang) =>
|
|
controller.GetActual(searchParams, version, lang))
|
|
.WithTags("Flights").WithSummary("Get actual (obsolete)");
|
|
|
|
endpoints.MapGet(
|
|
"api/Flights/{version:regex(^(1|1.0|v1|v1.0)$)}/{lang}/detailed", (
|
|
[FromServices] WebApi.Controllers.App.FlightsController controller,
|
|
HttpContext httpContext,
|
|
ClaimsPrincipal user,
|
|
[AsParameters] WebApi.Providers.SearchFlightParams searchParams,
|
|
string version,
|
|
string lang) =>
|
|
controller.GetDetailed(searchParams, version, lang))
|
|
.CacheOutput("DefaultDetails").WithTags("Flights").WithSummary("Get detailed (obsolete)");
|
|
|
|
endpoints.MapGet(
|
|
"api/Flights/{version:regex(^(1|1.0|v1|v1.0)$)}/{lang}/{requestType}/details", (
|
|
[FromServices] WebApi.Controllers.App.FlightsController controller,
|
|
HttpContext httpContext,
|
|
ClaimsPrincipal user,
|
|
[AsParameters] WebApi.Providers.SearchFlightParams searchParams,
|
|
string version,
|
|
string lang,
|
|
string requestType) =>
|
|
controller.GetDetails(searchParams, version, lang, requestType))
|
|
.CacheOutput("DefaultDetails").WithTags("Flights").WithSummary("Get details (obsolete)");
|
|
|
|
endpoints.MapGet(
|
|
"api/Flights/v{majorVersion:int}.{minorVersion:int:min(1)}/{lang}/{requestType}/details", (
|
|
[FromServices] WebApi.Controllers.App.FlightsController controller,
|
|
HttpContext httpContext,
|
|
ClaimsPrincipal user,
|
|
//[FromQuery] string[] flights, -- does not work as it worked in controllers!
|
|
//[FromQuery] DateTime[] dates,
|
|
[FromQuery] string departure,
|
|
[FromQuery] string arrival,
|
|
[FromRoute] int majorVersion,
|
|
[FromRoute] int minorVersion,
|
|
[FromRoute] string lang,
|
|
[FromRoute] string requestType) =>
|
|
{
|
|
var flights = new List<string>();
|
|
var dates = new List<DateTime>();
|
|
for (int i = 0; ; i++) {
|
|
if (httpContext.Request.Query.ContainsKey("flights[" + i + "]") && httpContext.Request.Query.ContainsKey("dates[" + i + "]"))
|
|
{
|
|
if (DateTime.TryParseExact(httpContext.Request.Query["dates[" + i + "]"].ToString(), "yyyy-MM-ddTHH:mm:ss", CultureInfo.InvariantCulture, DateTimeStyles.None, out var dt)) {
|
|
flights.Add(httpContext.Request.Query["flights[" + i + "]"]);
|
|
dates.Add(dt);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (httpContext.Request.Query.ContainsKey("flights") && httpContext.Request.Query.ContainsKey("dates"))
|
|
{
|
|
if (DateTime.TryParseExact(httpContext.Request.Query["dates"].ToString(), "yyyy-MM-ddTHH:mm:ss", CultureInfo.InvariantCulture, DateTimeStyles.None, out var dt))
|
|
{
|
|
flights.Add(httpContext.Request.Query["flights"]);
|
|
dates.Add(dt);
|
|
}
|
|
}
|
|
|
|
return controller.GetDetails(flights.ToArray(), dates.ToArray(), departure, arrival, majorVersion, minorVersion, lang, requestType);
|
|
})
|
|
.CacheOutput("DefaultDetails").WithTags("Flights").WithSummary("Get details");
|
|
|
|
//endpoints.MapPost(
|
|
// "api/Flights/updates", (
|
|
// [FromServices] WebApi.Controllers.App.FlightsController controller,
|
|
// HttpContext httpContext,
|
|
// ClaimsPrincipal user,
|
|
// [FromBody] List < FlightUpdateModel > flightsUpdate) =>
|
|
// controller.PostUpdateFlight(flightsUpdate))
|
|
// .WithTags("Flights").WithSummary("Post flight updates");
|
|
|
|
endpoints.MapGet(
|
|
"api/Flights/{version:regex(^(1|1.0|v1|v1.0)$)}/{lang}/destinations", (
|
|
[FromServices] WebApi.Controllers.App.FlightsController controller,
|
|
HttpContext httpContext,
|
|
[AsParameters] WebApi.Providers.SearchFlightParams searchParams,
|
|
[FromRoute] string version,
|
|
[FromRoute] string lang) =>
|
|
controller.GetDestinations(searchParams, lang))
|
|
.CacheOutput("DefaultSchedule").WithTags("Flights").WithSummary("Get destinations");
|
|
|
|
|
|
endpoints.MapGet(
|
|
"api/Flights/{version:regex(^(1|1.0|v1|v1.0)$)}/{lang}/days/{date}/{daysNum}/{type}/{request}/{requestType}", (
|
|
[FromServices] WebApi.Controllers.App.FlightsController controller,
|
|
HttpContext httpContext,
|
|
ClaimsPrincipal user,
|
|
[FromRoute] string version,
|
|
[FromRoute] string lang,
|
|
[FromRoute] DateTime date,
|
|
[FromRoute] int daysNum,
|
|
[FromRoute] string type,
|
|
[FromRoute] string request,
|
|
[FromRoute] string requestType) =>
|
|
controller.GetDays(version, lang, date, daysNum, type, request, requestType))
|
|
.CacheOutput("DefaultDetails").WithTags("Flights").WithSummary("Get flight days");
|
|
|
|
endpoints.MapGet(
|
|
"api/{version:regex(^(v1|v1.0)$)}/{language}/flights", (
|
|
[FromServices] WebApi.Controllers.Api.V1.Onlineboard.FlightsController controller,
|
|
HttpContext httpContext,
|
|
[FromRoute] string language,
|
|
[FromRoute] string version) =>
|
|
controller.SearchFlightsXml(httpContext, version, language))
|
|
.WithTags("Flights V1").WithSummary("Search onlineboard flights in xml");
|
|
|
|
endpoints.MapGet(
|
|
"api/{version:regex(^(v1|v1.0)$)}/{language}/flights.{format}", (
|
|
[FromServices] WebApi.Controllers.Api.V1.Onlineboard.FlightsController controller,
|
|
HttpContext httpContext,
|
|
[FromRoute] string language,
|
|
[FromRoute] string format,
|
|
[FromRoute] string version) =>
|
|
controller.SearchFlights(httpContext, version, language, format))
|
|
.WithTags("Flights V1").WithSummary("Search onlineboard flights in requested format");
|
|
|
|
|
|
endpoints.MapGet(
|
|
"api/v{version}/{language}/flight", (
|
|
[FromServices] WebApi.Controllers.Api.V1.Schedule.FlightController controller,
|
|
HttpContext httpContext,
|
|
[AsParameters] WebApi.Models.Schedule.ApiV1.SearchFlightParams searchParams,
|
|
[FromRoute] string language,
|
|
[FromRoute] double version) =>
|
|
controller.GetFlightXml(httpContext, version, language, searchParams))
|
|
.WithTags("Flights V1").WithSummary("Search schedule flights in xml");
|
|
|
|
endpoints.MapGet(
|
|
"api/v{version}/{language}/flight.{format}", (
|
|
[FromServices] WebApi.Controllers.Api.V1.Schedule.FlightController controller,
|
|
HttpContext httpContext,
|
|
[AsParameters] WebApi.Models.Schedule.ApiV1.SearchFlightParams searchParams,
|
|
[FromRoute] string language,
|
|
[FromRoute] string format,
|
|
[FromRoute] double version) =>
|
|
controller.GetFlight(httpContext, version, language, format, searchParams))
|
|
.WithTags("Flights V1").WithSummary("Search schedule flights in requested format");
|
|
|
|
endpoints.MapGet(
|
|
"api/v{version}/{language}/aircraft", (
|
|
[FromServices] WebApi.Controllers.Api.FlightsController controller,
|
|
HttpContext httpContext,
|
|
[FromRoute] string language,
|
|
[FromRoute] double version) =>
|
|
controller.GetAircraft(httpContext, version, language, "json"))
|
|
.WithTags("Flights V2").WithSummary("Flight aircraft");
|
|
|
|
endpoints.MapGet(
|
|
"api/v{version}/{language}/aircraft.{format}", (
|
|
[FromServices] WebApi.Controllers.Api.FlightsController controller,
|
|
HttpContext httpContext,
|
|
string format,
|
|
[FromRoute] string language,
|
|
[FromRoute] double version) =>
|
|
controller.GetAircraft(httpContext, version, language, format))
|
|
.WithTags("Flights V2").WithSummary("Flight aircraft");
|
|
|
|
endpoints.MapGet(
|
|
"api/v{version}/{language}/dates", (
|
|
[FromServices] WebApi.Controllers.Api.FlightsController controller,
|
|
HttpContext httpContext,
|
|
[FromRoute] string language,
|
|
[FromRoute] double version) =>
|
|
controller.GetDates(httpContext, version, language, "json"))
|
|
.WithTags("Flights V2").WithSummary("Flight dates");
|
|
|
|
endpoints.MapGet(
|
|
"api/v{version}/{language}/dates.{format}", (
|
|
[FromServices] WebApi.Controllers.Api.FlightsController controller,
|
|
HttpContext httpContext,
|
|
string format,
|
|
[FromRoute] string language,
|
|
[FromRoute] double version) =>
|
|
controller.GetDates(httpContext, version, language, format))
|
|
.WithTags("Flights V2").WithSummary("Flight dates");
|
|
|
|
endpoints.MapGet(
|
|
"api/v{version:regex(^2)}/{lang}/flights",
|
|
[AllowAnonymous]
|
|
[Authorize(Policy = "policyjwt")]
|
|
[Authorize(Policy = "policycookie")]
|
|
(
|
|
[FromServices] WebApi.Controllers.Api.FlightsController controller,
|
|
HttpContext httpContext,
|
|
ClaimsPrincipal user,
|
|
[FromRoute] string lang,
|
|
[FromRoute] double version) =>
|
|
controller.GetFlights(httpContext, user, version, lang, "json"))
|
|
.WithTags("Flights V2").WithSummary("Search flights in xml");
|
|
|
|
endpoints.MapGet(
|
|
"api/v{version:regex(^2)}/{lang}/flights.{format}",
|
|
[AllowAnonymous]
|
|
[Authorize(Policy = "policyjwt")]
|
|
[Authorize(Policy = "policycookie")]
|
|
(
|
|
[FromServices] WebApi.Controllers.Api.FlightsController controller,
|
|
HttpContext httpContext,
|
|
ClaimsPrincipal user,
|
|
[FromRoute] string lang,
|
|
[FromRoute] string format,
|
|
[FromRoute] double version) =>
|
|
controller.GetFlights(httpContext, user, version, lang, format))
|
|
.WithTags("Flights V2").WithSummary("Search flights in requested format");
|
|
|
|
|
|
|
|
endpoints.MapGet(
|
|
"/api/Requests/{version}/GetPopular",
|
|
([FromServices] WebApi.Controllers.App.RequestsController controller,
|
|
string version) =>
|
|
controller.GetPopular()).Produces<IEnumerable<IPopularRequest>>(StatusCodes.Status200OK)
|
|
.CacheOutput("Requests").WithTags("Requests").WithSummary("Get populer requests");
|
|
|
|
endpoints.MapGet(
|
|
"/api/Version",
|
|
([FromServices] WebApi.Controllers.App.VersionController controller) =>
|
|
controller.Get()).Produces<string>(StatusCodes.Status200OK)
|
|
.WithTags("Version").WithSummary("Get version");
|
|
|
|
endpoints.MapControllerRoute(
|
|
name: "Flights",
|
|
pattern: "api/{version}/{**url}",
|
|
defaults: new { controller = "ExtFlights", action = "GetNotFound" },
|
|
constraints: new { version = @"v1(\.0)?", url = @".*/extflights.*" });
|
|
|
|
|
|
endpoints.MapControllerRoute(
|
|
name: "Flights",
|
|
pattern: "api/{version}/{**url}",
|
|
defaults: new { controller = "Airport", action = "GetNotFound" },
|
|
constraints: new { url = @".*/airport.*", version = @"v1(\.(1|0))?" });
|
|
|
|
endpoints.MapControllerRoute(
|
|
name: "Flights",
|
|
pattern: "{**url}",
|
|
defaults: new { controller = "Airport", action = "GetNotFound" },
|
|
constraints: new { url = @".*/airports.*" });
|
|
|
|
endpoints.MapControllerRoute(
|
|
name: "Flights",
|
|
pattern: "api/{version}/{**url}",
|
|
defaults: new { controller = "Schedule", action = "GetNotFound" },
|
|
constraints: new { url = @".*/schedule.*", version = @"v1(\.0)?" });
|
|
|
|
endpoints.Map("/{country}-{lang}/404", context =>
|
|
{
|
|
// this is because it asked to return 404 (nobody cares that we are on SPA, and it should be handled by SSR + ng Universal)
|
|
context.Response.StatusCode = 404;
|
|
return Task.CompletedTask;
|
|
});
|
|
endpoints.Map("/{country}-{lang}/500", context =>
|
|
{
|
|
// this is because it asked to return 500 (nobody cares that we are on SPA, and it should be handled by SSR + ng Universal)
|
|
context.Response.StatusCode = 500;
|
|
return Task.CompletedTask;
|
|
});
|
|
endpoints.MapControllers();
|
|
endpoints.MapDefaultControllerRoute();
|
|
endpoints.MapRazorPages();
|
|
//endpoints.MapHub<FlightHub>("/flights");
|
|
|
|
endpoints.MapMetrics(Configuration["Prometheus:Url"]);
|
|
});
|
|
|
|
if (!String.IsNullOrEmpty(Configuration["Swagger:Password"]))
|
|
{
|
|
app.UseSwaggerAuthorized();
|
|
app.UseSwagger();
|
|
app.UseSwaggerUI(c =>
|
|
{
|
|
c.SwaggerEndpoint("/swagger/v1/swagger.json", "Flights");
|
|
c.EnableTryItOutByDefault();
|
|
});
|
|
}
|
|
|
|
app.UseSpa(spa =>
|
|
{
|
|
spa.Options.SourcePath = "ClientApp";
|
|
spa.Options.StartupTimeout = new TimeSpan(0, 5, 0);
|
|
|
|
if (env.IsDevelopment() && !Configuration.GetValue<bool>("DOTNET_RUNNING_IN_CONTAINER"))
|
|
{
|
|
spa.UseAngularCliServer(npmScript: "start");
|
|
}
|
|
});
|
|
}
|
|
|
|
private void ConfigureAuthService(IServiceCollection services, IConfiguration configuration)
|
|
{
|
|
var identityAuthority = configuration.GetSection("Identity").GetValue<string>("Authority");
|
|
var identityClientId = configuration.GetSection("Identity").GetValue<string>("ClientId");
|
|
var identityClientSecret = configuration.GetSection("Identity").GetValue<string>("ClientSecret");
|
|
|
|
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
|
|
|
|
services.AddAuthentication(options =>
|
|
{
|
|
options.DefaultScheme = "Cookies";
|
|
options.DefaultChallengeScheme = "oidc";
|
|
})
|
|
.AddCookie()
|
|
.AddOpenIdConnect("oidc", options =>
|
|
{
|
|
options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
|
|
options.Authority = identityAuthority;
|
|
|
|
options.ClientId = identityClientId;
|
|
options.ClientSecret = identityClientSecret;
|
|
options.ResponseType = OpenIdConnectResponseType.Code;
|
|
options.CallbackPath = "/admin/signin-oidc";
|
|
|
|
options.SaveTokens = true;
|
|
options.GetClaimsFromUserInfoEndpoint = true;
|
|
options.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters() { ValidateIssuer = true };
|
|
options.Scope.Add("profile");
|
|
options.Scope.Add("openid");
|
|
options.Scope.Add("offline_access");
|
|
|
|
//options.Events = new OpenIdConnectEvents
|
|
//{
|
|
// OnAuthorizationCodeReceived = async context =>
|
|
// {
|
|
// var code = context.ProtocolMessage.Code;
|
|
// var identifier = context.Principal;
|
|
// await Task.Yield();
|
|
// },
|
|
// OnMessageReceived = async ctxt =>
|
|
// {
|
|
// string bodyContent = new StreamReader(ctxt.Request.Body).ReadToEnd();
|
|
// await Task.Yield();
|
|
// },
|
|
// OnTicketReceived = async ctxt =>
|
|
// {
|
|
// await Task.Yield();
|
|
// },
|
|
// OnTokenValidated = async ctx =>
|
|
// {
|
|
// var userID = ctx.Principal.FindFirstValue("sub");
|
|
|
|
// },
|
|
//OnRemoteFailure = ctx => {
|
|
// ctx.HandleResponse();
|
|
// //ctx.Response.Redirect("~/Information");
|
|
// return Task.FromResult(0);
|
|
// }
|
|
//};
|
|
});
|
|
}
|
|
|
|
public record CaseInsensitive<T>(T Value)
|
|
where T : struct, Enum
|
|
{
|
|
public static bool TryParse(string? value, IFormatProvider? provider, out CaseInsensitive<T>? val)
|
|
{
|
|
if (Enum.TryParse<T>(value, ignoreCase: true, out var enumVal))
|
|
{
|
|
val = new CaseInsensitive<T>(enumVal);
|
|
return true;
|
|
}
|
|
|
|
val = null;
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|