Add rider files and use options #58

Open
Egamorf wants to merge 2 commits from feature/fix-editor-and-options into main
5 changed files with 69 additions and 51 deletions
Showing only changes of commit 36360efa6f - Show all commits

View File

@@ -0,0 +1,3 @@
namespace GameIdeas.Shared.Exceptions;
public class EnvironmentVariableMissingException(string message) : Exception(message);

View File

@@ -0,0 +1,47 @@
using GameIdeas.Shared.Exceptions;
using GameIdeas.Shared.Options;
namespace GameIdeas.WebAPI.Extensions;
public static class ServiceCollectionExtension
{
public static IServiceCollection AddGameIdeasOptions(this IServiceCollection services)
{
#if DEBUG
var dictionary = LoadEnvironmentVariable("../../../../.env");
#else
var dictionary = LoadEnvironmentVariable("../.env");
#endif
services.Configure<GameIdeasOptions>(options =>
{
options.DbHost = GetEnvVar("DB_HOST", dictionary);
options.DbUsername = GetEnvVar("DB_USERNAME", dictionary);
options.DbPassword = GetEnvVar("DB_PASSWORD", dictionary);
options.DbDatabase = GetEnvVar("DB_DATABASE", dictionary);
options.JwtKey = GetEnvVar("JWT_KEY", dictionary);
options.JwtIssuer = GetEnvVar("JWT_ISSUER", dictionary);
options.JwtAudience = GetEnvVar("JWT_AUDIENCE", dictionary);
});
return services;
}
private static string GetEnvVar(string name, Dictionary<string, string> dictionary)
{
return Environment.GetEnvironmentVariable(name)
?? dictionary.GetValueOrDefault(name)
?? throw new EnvironmentVariableMissingException($"Missing environment variable with key: {name}");
}
private static Dictionary<string, string> LoadEnvironmentVariable(string filePath)
{
if (!File.Exists(filePath))
return [];
return File.ReadAllLines(filePath)
.Select(line => line.Split('=', StringSplitOptions.RemoveEmptyEntries))
.Where(parts => parts.Length == 2)
.ToDictionary(parts => parts[0], parts => parts[1]);
}
}

View File

@@ -28,8 +28,4 @@
<ProjectReference Include="..\..\GameIdeas.Shared\GameIdeas.Shared.csproj" />
</ItemGroup>
<ItemGroup>
<Folder Include="Extensions\" />
</ItemGroup>
</Project>

View File

@@ -10,37 +10,18 @@ using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.IdentityModel.Tokens;
using System.Text;
using GameIdeas.WebAPI.Extensions;
var builder = WebApplication.CreateBuilder(args);
var services = builder.Services;
#if DEBUG
LoadEnvironmentVariable("../../../../.env");
#else
LoadEnvironmentVariable("../.env");
#endif
Action<DbContextOptionsBuilder> dbContextOptions = options =>
{
options.UseNpgsql(
GetConnectionString(),
npgOption =>
{
npgOption.CommandTimeout(60);
npgOption.MigrationsAssembly("GameIdeas.WebAPI");
});
};
// Add services to the container.
services.AddDbContext<GameIdeasContext>(dbContextOptions);
services.AddGameIdeasOptions();
services.AddDbContext<GameIdeasContext>(ContextOptions);
services.AddIdentity<User, IdentityRole>()
.AddEntityFrameworkStores<GameIdeasContext>()
.AddDefaultTokenProviders();
var jwtKey = Environment.GetEnvironmentVariable("JWT_KEY")
?? throw new ArgumentNullException(message: "Invalid key for JWT token", null);
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
@@ -86,7 +67,6 @@ services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies());
services.AddControllers();
// Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi
services.AddOpenApi();
services.AddCors(option => option.AddDefaultPolicy(policy =>
@@ -118,6 +98,16 @@ app.UseAuthorization();
app.MapControllers();
app.Run();
return;
void ContextOptions(DbContextOptionsBuilder options)
{
options.UseNpgsql(GetConnectionString(), npgOption =>
{
npgOption.CommandTimeout(60);
npgOption.MigrationsAssembly("GameIdeas.WebAPI");
});
}
async Task LoadTranslations()
{
@@ -145,21 +135,3 @@ string GetConnectionString()
return $"Host={host};Username={login};Password={pass};Database={database}";
}
static void LoadEnvironmentVariable(string filePath)
{
if (!File.Exists(filePath))
return;
foreach (var line in File.ReadAllLines(filePath))
{
var parts = line.Split(
'=',
StringSplitOptions.RemoveEmptyEntries);
if (parts.Length != 2)
continue;
Environment.SetEnvironmentVariable(parts[0], parts[1]);
}
}

View File

@@ -11,12 +11,15 @@ using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using GameIdeas.Shared.Exceptions;
using GameIdeas.Shared.Options;
using Microsoft.Extensions.Options;
namespace GameIdeas.WebAPI.Services.Users;
public class UserReadService(
UserManager<User> userManager,
GameIdeasContext context,
IOptions<GameIdeasOptions> options,
IMapper mapper) : IUserReadService
{
public async Task<IEnumerable<RoleDto>> GetRoles()
@@ -125,14 +128,11 @@ public class UserReadService(
authClaims.AddRange((await userManager.GetRolesAsync(user))
.Select(r => new Claim(ClaimTypes.Role, r)));
var jwtKey = Environment.GetEnvironmentVariable("JWT_KEY")
?? throw new ArgumentNullException(message: ResourcesKey.InvalidToken, null);
var authSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtKey));
var authSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(options.Value.JwtKey));
var token = new JwtSecurityToken(
issuer: Environment.GetEnvironmentVariable("JWT_ISSUER"),
audience: Environment.GetEnvironmentVariable("JWT_AUDIENCE"),
issuer: options.Value.JwtIssuer,
audience: options.Value.JwtAudience,
expires: DateTime.Now.AddHours(GlobalConstants.JWT_DURATION_HOUR),
claims: authClaims,
signingCredentials: new SigningCredentials(authSigningKey, SecurityAlgorithms.HmacSha256)