diff --git a/HackathonPreparing/HackathonPreparing/HackathonPreparing.ApiService/Features/AuthFeature/EfCore/UserContext.cs b/HackathonPreparing/HackathonPreparing/HackathonPreparing.ApiService/Features/AuthFeature/EfCore/UserContext.cs index fec04ac..6b09dd5 100644 --- a/HackathonPreparing/HackathonPreparing/HackathonPreparing.ApiService/Features/AuthFeature/EfCore/UserContext.cs +++ b/HackathonPreparing/HackathonPreparing/HackathonPreparing.ApiService/Features/AuthFeature/EfCore/UserContext.cs @@ -4,16 +4,19 @@ using Microsoft.EntityFrameworkCore; namespace HackathonPreparing.ApiService.AuthFeature.EfCore; -public class UserContext : IdentityDbContext, int> +public class UserContext : IdentityDbContext, int> { - public UserContext (DbContextOptions options) : base(options) {} + public UserContext (DbContextOptions options) : base(options) + { + + } protected override void OnModelCreating(ModelBuilder builder) { base.OnModelCreating(builder); - builder.ApplyConfigurationsFromAssembly(typeof(Program).Assembly); builder.HasDefaultSchema("user"); + builder.ApplyConfigurationsFromAssembly(typeof(Program).Assembly); } } \ No newline at end of file diff --git a/HackathonPreparing/HackathonPreparing/HackathonPreparing.ApiService/Features/DevFeature/DbHelpersEndpointsExtensions.cs b/HackathonPreparing/HackathonPreparing/HackathonPreparing.ApiService/Features/DevFeature/DbHelpersEndpointsExtensions.cs index 657305e..9f27664 100644 --- a/HackathonPreparing/HackathonPreparing/HackathonPreparing.ApiService/Features/DevFeature/DbHelpersEndpointsExtensions.cs +++ b/HackathonPreparing/HackathonPreparing/HackathonPreparing.ApiService/Features/DevFeature/DbHelpersEndpointsExtensions.cs @@ -2,6 +2,8 @@ using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using Swashbuckle.AspNetCore.SwaggerGen; +using static HackathonPreparing.ApiService.Features.DevFeature.ReflectionHelpers; + namespace HackathonPreparing.ApiService.DevFeature; @@ -9,21 +11,15 @@ public static class DbHelpersEndpointsExtensions { public static RouteGroupBuilder AddDbHelpersEndpoints(this WebApplication app) { - var group = app.MapGroup("/db"); + var group = app.MapGroup("db"); group.MapPost("/migrate/{contexClassName}", async (string contexClasstName, IServiceProvider services) => { - var contextType = typeof(Program).Assembly.GetType(contexClasstName); + var contextType = GetEfCoreClassContexts().FirstOrDefault(c => c.Name == contexClasstName); if(contextType is null) return Results.NotFound(); - var inheritanceChain = contextType.GetInheritanceChain(); - - if(!inheritanceChain.Any(t => typeof(DbContext) == t)) - return Results.NotFound(); - - using var scope = services.CreateScope(); var dbContext = (DbContext)scope.ServiceProvider.GetRequiredService(contextType); @@ -34,17 +30,11 @@ public static class DbHelpersEndpointsExtensions group.MapPost("/initdb/{contexClassName}", async (string contexClasstName, IServiceProvider services) => { - var contextType = typeof(Program).Assembly.GetType(contexClasstName); + var contextType = GetEfCoreClassContexts().FirstOrDefault(c => c.Name == contexClasstName); if(contextType is null) return Results.NotFound(); - var inheritanceChain = contextType.GetInheritanceChain(); - - if(!inheritanceChain.Any(t => typeof(DbContext) == t)) - return Results.NotFound(); - - using var scope = services.CreateScope(); var dbContext = (DbContext)scope.ServiceProvider.GetRequiredService(contextType); @@ -53,6 +43,33 @@ public static class DbHelpersEndpointsExtensions return Results.Ok(); }); + group.MapPost("/initdb", async (IServiceProvider services) => + { + foreach(var contextType in GetEfCoreClassContexts()) + { + using var scope = services.CreateScope(); + + var dbContext = (DbContext)scope.ServiceProvider.GetRequiredService(contextType); + + await dbContext.Database.EnsureCreatedAsync(); + } + return Results.Ok(); + }); + + group.MapPost("/migrate", async (IServiceProvider services) => + { + foreach(var contextType in GetEfCoreClassContexts()) + { + using var scope = services.CreateScope(); + + var dbContext = (DbContext)scope.ServiceProvider.GetRequiredService(contextType); + + await dbContext.Database.MigrateAsync(); + } + return Results.Ok(); + }); + + group.MapPost("/add-moderator", async ([FromServices]UserManager userManager) => { var user = new AuthFeature.User{ Email = "m@gmail.com", diff --git a/HackathonPreparing/HackathonPreparing/HackathonPreparing.ApiService/Features/DevFeature/ReflectionHelpers.cs b/HackathonPreparing/HackathonPreparing/HackathonPreparing.ApiService/Features/DevFeature/ReflectionHelpers.cs new file mode 100644 index 0000000..a75fbd6 --- /dev/null +++ b/HackathonPreparing/HackathonPreparing/HackathonPreparing.ApiService/Features/DevFeature/ReflectionHelpers.cs @@ -0,0 +1,28 @@ +using Microsoft.EntityFrameworkCore; +using Swashbuckle.AspNetCore.SwaggerGen; + +namespace HackathonPreparing.ApiService.Features.DevFeature; + +public static class ReflectionHelpers +{ + private static IEnumerable? EfCoreDbContexts; + + // !!!! + // DONT USE FOR HIGH CONCURANCY TASKS + // IT NOT FOR MULTITHREADING CODE + // OF FOR MANY REQUESTS PER MINUTE + // !!!! + + public static IEnumerable GetEfCoreClassContexts() + { + + if(EfCoreDbContexts is null) + { + //Get all types with DbContext parent type + EfCoreDbContexts = typeof(Program).Assembly.GetTypes().Where(t => + t.GetInheritanceChain().Any(inheritanType => + inheritanType.Name is not null && inheritanType.Name == nameof(DbContext))); + } + return EfCoreDbContexts; + } +} \ No newline at end of file diff --git a/HackathonPreparing/HackathonPreparing/HackathonPreparing.ApiService/Features/DevFeature/ServicesExtensions.cs b/HackathonPreparing/HackathonPreparing/HackathonPreparing.ApiService/Features/DevFeature/ServicesExtensions.cs index ce6d64e..fca108d 100644 --- a/HackathonPreparing/HackathonPreparing/HackathonPreparing.ApiService/Features/DevFeature/ServicesExtensions.cs +++ b/HackathonPreparing/HackathonPreparing/HackathonPreparing.ApiService/Features/DevFeature/ServicesExtensions.cs @@ -12,4 +12,13 @@ public static class ServicesExtensions optionsBuilder => optionsBuilder.UseNpgsql(npgsqlBuilder => npgsqlBuilder.MigrationsAssembly(typeof(Program).Assembly.GetName().Name))); } + + // public static void AddDbContextWithDefaultConfiguration(this WebApplicationBuilder builder) where TDbContext : DbContext + // { + // var connection = builder.Configuration.GetConnectionString("prod") ?? throw new NullReferenceException("CONNECTION TO POSTGRES IS NULL"); + + // builder.Services.AddDbContext(b => b.UseNpgsql(connection, npgsqlBuilder => + // npgsqlBuilder.MigrationsAssembly(typeof(Program).Assembly.GetName().Name))); + // } + } \ No newline at end of file diff --git a/HackathonPreparing/HackathonPreparing/HackathonPreparing.ApiService/Features/WeatherForecastFeature/EfCore/WeatherForecastContext.cs b/HackathonPreparing/HackathonPreparing/HackathonPreparing.ApiService/Features/WeatherForecastFeature/EfCore/WeatherForecastContext.cs index 16a5866..90ee378 100644 --- a/HackathonPreparing/HackathonPreparing/HackathonPreparing.ApiService/Features/WeatherForecastFeature/EfCore/WeatherForecastContext.cs +++ b/HackathonPreparing/HackathonPreparing/HackathonPreparing.ApiService/Features/WeatherForecastFeature/EfCore/WeatherForecastContext.cs @@ -10,12 +10,12 @@ public sealed class WeatherForecastContext : DbContext } - public DbSet Forecasts => Set(); + public DbSet Forecasts => Set(); protected override void OnModelCreating(ModelBuilder builder) { base.OnModelCreating(builder); - builder.ApplyConfigurationsFromAssembly(typeof(Program).Assembly); builder.HasDefaultSchema("weatherforecast"); + builder.ApplyConfigurationsFromAssembly(typeof(Program).Assembly); } } diff --git a/HackathonPreparing/HackathonPreparing/HackathonPreparing.ApiService/Features/WeatherForecastFeature/WeatherForecastEndpointsExtensions.cs b/HackathonPreparing/HackathonPreparing/HackathonPreparing.ApiService/Features/WeatherForecastFeature/WeatherForecastEndpointsExtensions.cs index 2830ab8..2318136 100644 --- a/HackathonPreparing/HackathonPreparing/HackathonPreparing.ApiService/Features/WeatherForecastFeature/WeatherForecastEndpointsExtensions.cs +++ b/HackathonPreparing/HackathonPreparing/HackathonPreparing.ApiService/Features/WeatherForecastFeature/WeatherForecastEndpointsExtensions.cs @@ -1,5 +1,6 @@ using HackathonPreparing.ApiService.WeatherForecastFeature.EfCore; using Microsoft.EntityFrameworkCore; +using Microsoft.AspNetCore.Authorization; namespace HackathonPreparing.ApiService.WeatherForecastFeature; @@ -7,9 +8,9 @@ public static class WeatherForecastEndpointsExtensions { public static void AddWeatherForecastEndpoints (this WebApplication app) { - var group = app.MapGroup("/weatherforecast"); - group.MapGet("/", async (WeatherForecastContext db) => await db.Forecasts.ToListAsync()); - group.MapDelete("/{id}", async (WeatherForecastContext db, int id) => + var group = app.MapGroup("weatherforecast"); + group.MapGet(string.Empty, async (WeatherForecastContext db) => await db.Forecasts.ToListAsync()); + group.MapDelete("{id}", [Authorize(Roles="moderator")]async (WeatherForecastContext db, int id) => { var forecast = await db.Forecasts.FindAsync(id); if (forecast == null) @@ -21,15 +22,15 @@ public static class WeatherForecastEndpointsExtensions await db.SaveChangesAsync(); return Results.NoContent(); - }).RequireAuthorization("moderator"); - group.MapPost("/", async (WeatherForecastContext db, ApiService.WeatherForecastFeature.WeatherForecast forecast) => + }); + group.MapPost(string.Empty, [Authorize(Roles="moderator")] async (WeatherForecastContext db, WeatherForecast forecast) => { db.Forecasts.Add(forecast); await db.SaveChangesAsync(); return Results.Created($"/weatherforecast/{forecast.Id}", forecast); }); - group.MapPut("/{id}", async (WeatherForecastContext db, int id, ApiService.WeatherForecastFeature.WeatherForecast forecast) => + group.MapPut("{id}", [Authorize(Roles="moderator")] async (WeatherForecastContext db, int id, WeatherForecast forecast) => { if (id != forecast.Id) { @@ -53,7 +54,7 @@ public static class WeatherForecastEndpointsExtensions } return Results.NoContent(); - }).RequireAuthorization("moderator"); + }); group.WithTags("weatherforecast"); } } \ No newline at end of file diff --git a/HackathonPreparing/HackathonPreparing/HackathonPreparing.ApiService/HackathonPreparing.ApiService.csproj b/HackathonPreparing/HackathonPreparing/HackathonPreparing.ApiService/HackathonPreparing.ApiService.csproj index 3645b3f..dbf01af 100644 --- a/HackathonPreparing/HackathonPreparing/HackathonPreparing.ApiService/HackathonPreparing.ApiService.csproj +++ b/HackathonPreparing/HackathonPreparing/HackathonPreparing.ApiService/HackathonPreparing.ApiService.csproj @@ -12,6 +12,7 @@ + diff --git a/HackathonPreparing/HackathonPreparing/HackathonPreparing.ApiService/Program.cs b/HackathonPreparing/HackathonPreparing/HackathonPreparing.ApiService/Program.cs index bc431c7..e01207e 100644 --- a/HackathonPreparing/HackathonPreparing/HackathonPreparing.ApiService/Program.cs +++ b/HackathonPreparing/HackathonPreparing/HackathonPreparing.ApiService/Program.cs @@ -4,7 +4,6 @@ using HackathonPreparing.ApiService.DevFeature; using HackathonPreparing.ApiService.WeatherForecastFeature; using HackathonPreparing.ApiService.WeatherForecastFeature.EfCore; using HackathonPreparing.ServiceDefaults; -using Microsoft.AspNetCore.Identity; using Microsoft.OpenApi.Models; var builder = WebApplication.CreateBuilder(args); @@ -43,16 +42,12 @@ builder.Services.AddSwaggerGen(c => builder.Services.AddAuthorization(); -builder.Services.AddAuthorizationBuilder() - .AddPolicy("moderator", policy => - policy.RequireRole("MODERATOR")); -//TODO BEARER -builder.Services.AddAuthentication().AddBearerToken(IdentityConstants.BearerScheme); +builder.Services.AddAuthentication().AddBearerToken(); -builder.Services.AddIdentity>() - .AddEntityFrameworkStores() - .AddApiEndpoints(); +builder.Services + .AddIdentityApiEndpoints() + .AddEntityFrameworkStores(); // Add services to the container. builder.Services.AddProblemDetails(); @@ -62,7 +57,12 @@ builder.AddDbContextWithDefaultConfiguration(); var app = builder.Build(); -app.UsePathBase(new PathString("/api")); + + +app.UsePathBase("/api"); +app.UseRouting(); + +app.MapGet("/test", () => {}); if (app.Environment.IsDevelopment()) { @@ -73,16 +73,21 @@ if (app.Environment.IsDevelopment()) app.AddDbHelpersEndpoints(); } -// Configure the HTTP request pipeline. + + +//Configure the HTTP request pipeline. app.UseExceptionHandler(); -app.UseAuthorization(); + app.UseAuthentication(); +app.UseAuthorization(); + app.AddWeatherForecastEndpoints(); - app.MapDefaultEndpoints(); -app.MapGroup("/user") + + +app.MapGroup("user") .MapIdentityApi() .WithTags("user"); diff --git a/HackathonPreparing/HackathonPreparing/HackathonPreparing.ApiService/appsettings.json b/HackathonPreparing/HackathonPreparing/HackathonPreparing.ApiService/appsettings.json index 10f68b8..5a8344b 100644 --- a/HackathonPreparing/HackathonPreparing/HackathonPreparing.ApiService/appsettings.json +++ b/HackathonPreparing/HackathonPreparing/HackathonPreparing.ApiService/appsettings.json @@ -5,5 +5,8 @@ "Microsoft.AspNetCore": "Warning" } }, - "AllowedHosts": "*" + "AllowedHosts": "*", + "ConnectionStrings": { + "prod": "User ID=postgres;Password=postgres;Host=localhost;Port=5432;Database=prod;" + } }