Docker aplicado

This commit is contained in:
Eduardo 2026-02-09 18:00:47 -03:00
parent 142bb60967
commit b924397f52
9 changed files with 84 additions and 124 deletions

11
.dockerignore Normal file
View File

@ -0,0 +1,11 @@
.git
.github
.vs
bin
obj
**/bin
**/obj
*.user
*.suo
*.log
README.md

View File

@ -1,60 +0,0 @@
using line_gestao_api.Models;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
namespace line_gestao_api.Controllers;
[ApiController]
[Route("dev")]
public class DevController : ControllerBase
{
private readonly UserManager<ApplicationUser> _userManager;
private readonly IConfiguration _config;
private readonly IWebHostEnvironment _env;
public DevController(
UserManager<ApplicationUser> userManager,
IConfiguration config,
IWebHostEnvironment env)
{
_userManager = userManager;
_config = config;
_env = env;
}
/// <summary>
/// Reseta a senha do admin seeded (somente em Development).
/// </summary>
[HttpPost("reset-admin-password")]
public async Task<IActionResult> ResetAdminPassword()
{
// 🔒 Proteção: só funciona em Development
if (!_env.IsDevelopment())
return NotFound();
var email = (_config["Seed:AdminEmail"] ?? "admin@linegestao.local").Trim().ToLowerInvariant();
var newPassword = _config["Seed:AdminPassword"] ?? "Admin123!";
var normalizedEmail = _userManager.NormalizeEmail(email);
var user = await _userManager.Users
.FirstOrDefaultAsync(u => u.NormalizedEmail == normalizedEmail);
if (user == null)
return NotFound("Admin não encontrado.");
// remove lockout se existir (só pra garantir)
await _userManager.SetLockoutEndDateAsync(user, null);
await _userManager.ResetAccessFailedCountAsync(user);
// reseta senha corretamente (via Identity)
var token = await _userManager.GeneratePasswordResetTokenAsync(user);
var reset = await _userManager.ResetPasswordAsync(user, token, newPassword);
if (!reset.Succeeded)
return BadRequest(reset.Errors.Select(e => e.Description));
return Ok($"Senha do admin resetada com sucesso para: {newPassword}");
}
}

View File

@ -1,26 +0,0 @@
using Microsoft.AspNetCore.Mvc;
namespace line_gestao_api.Controllers
{
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
private static readonly string[] Summaries =
[
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
];
[HttpGet(Name = "GetWeatherForecast")]
public IEnumerable<WeatherForecast> Get()
{
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
})
.ToArray();
}
}
}

20
Dockerfile Normal file
View File

@ -0,0 +1,20 @@
FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
WORKDIR /src
COPY ["line-gestao-api.csproj", "./"]
RUN dotnet restore "./line-gestao-api.csproj"
COPY . .
RUN dotnet publish "./line-gestao-api.csproj" -c Release -o /app/publish /p:UseAppHost=false
FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS final
WORKDIR /app
ENV ASPNETCORE_URLS=http://+:8080
ENV ASPNETCORE_ENVIRONMENT=Production
COPY --from=build /app/publish .
EXPOSE 8080
ENTRYPOINT ["dotnet", "line-gestao-api.dll"]

View File

@ -12,23 +12,34 @@ var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
// ✅ Upload (Excel / multipart)
builder.Services.Configure<FormOptions>(o =>
{
o.MultipartBodyLengthLimit = 50_000_000;
});
// ✅ CORS (Angular)
var corsOrigins = builder.Configuration
.GetSection("Cors:AllowedOrigins")
.Get<string[]>()?
.Where(o => !string.IsNullOrWhiteSpace(o))
.Select(o => o.Trim())
.Distinct(StringComparer.OrdinalIgnoreCase)
.ToArray()
?? [];
if (corsOrigins.Length == 0)
{
corsOrigins = ["http://localhost:4200"];
}
builder.Services.AddCors(options =>
{
options.AddPolicy("Front", p =>
p.WithOrigins("http://localhost:4200")
p.WithOrigins(corsOrigins)
.AllowAnyHeader()
.AllowAnyMethod()
);
});
// ✅ EF Core (PostgreSQL)
builder.Services.AddDbContext<AppDbContext>(options =>
options.UseNpgsql(builder.Configuration.GetConnectionString("Default"))
);
@ -49,12 +60,15 @@ builder.Services.AddIdentityCore<ApplicationUser>(options =>
.AddEntityFrameworkStores<AppDbContext>()
.AddDefaultTokenProviders();
// ✅ Swagger
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
// ✅ JWT
var jwtKey = builder.Configuration["Jwt:Key"]!;
var jwtKey = builder.Configuration["Jwt:Key"];
if (string.IsNullOrWhiteSpace(jwtKey))
{
throw new InvalidOperationException("Configuration 'Jwt:Key' is required.");
}
var issuer = builder.Configuration["Jwt:Issuer"];
var audience = builder.Configuration["Jwt:Audience"];
@ -89,18 +103,21 @@ if (app.Environment.IsDevelopment())
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
var useHttpsRedirection = builder.Configuration.GetValue("App:UseHttpsRedirection", !app.Environment.IsDevelopment());
if (useHttpsRedirection)
{
app.UseHttpsRedirection();
}
// ✅ CORS antes de Auth
app.UseCors("Front");
app.UseAuthentication();
app.UseMiddleware<TenantMiddleware>();
app.UseAuthorization();
// ✅ SEED ANTES de subir controllers
await SeedData.EnsureSeedDataAsync(app.Services);
app.MapControllers();
app.MapGet("/health", () => Results.Ok(new { status = "ok" }));
app.Run();

View File

@ -1,13 +0,0 @@
namespace line_gestao_api
{
public class WeatherForecast
{
public DateOnly Date { get; set; }
public int TemperatureC { get; set; }
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
public string? Summary { get; set; }
}
}

View File

@ -1,4 +1,21 @@
{
"ConnectionStrings": {
"Default": "Host=localhost;Port=5432;Database=linegestao;Username=linegestao_app;Password=CHANGE_ME"
},
"Jwt": {
"Key": "dev-only-please-replace-with-env-variable-in-production",
"Issuer": "LineGestao",
"Audience": "LineGestao",
"ExpiresMinutes": 360
},
"Cors": {
"AllowedOrigins": [
"http://localhost:4200"
]
},
"App": {
"UseHttpsRedirection": false
},
"Logging": {
"LogLevel": {
"Default": "Information",

View File

@ -1,13 +1,19 @@
{
"ConnectionStrings": {
"Default": "Host=localhost;Port=5432;Database=linegestao;Username=linegestao_app;Password=255851Ed@"
"Default": "Host=localhost;Port=5432;Database=linegestao;Username=linegestao_app;Password=CHANGE_ME"
},
"Jwt": {
"Key": "vI8/oEYEWN5sBDTisNuZFjZAl+YFvXEJ96POb73/eoq3NaFPkOFXyPRdf/HWGAFnUsF3e3QpYL6Wl4Bc2v+l3g==",
"Key": "",
"Issuer": "LineGestao",
"Audience": "LineGestao",
"ExpiresMinutes": 360
},
"Cors": {
"AllowedOrigins": [ "http://localhost:4200" ]
},
"App": {
"UseHttpsRedirection": true
},
"Notifications": {
"CheckIntervalMinutes": 60,
"ReminderDays": [30, 15, 7]
@ -16,6 +22,6 @@
"DefaultTenantName": "Default",
"AdminName": "Administrador",
"AdminEmail": "admin@linegestao.local",
"AdminPassword": "Admin123!"
"AdminPassword": "CHANGE_ME"
}
}

View File

@ -10,13 +10,6 @@
<UseAppHost>false</UseAppHost>
</PropertyGroup>
<ItemGroup>
<Compile Remove="NovaPasta\**" />
<Content Remove="NovaPasta\**" />
<EmbeddedResource Remove="NovaPasta\**" />
<None Remove="NovaPasta\**" />
</ItemGroup>
<ItemGroup>
<Compile Remove="line-gestao-api.Tests\**" />
<Content Remove="line-gestao-api.Tests\**" />
@ -24,11 +17,6 @@
<None Remove="line-gestao-api.Tests\**" />
</ItemGroup>
<ItemGroup>
<Compile Remove="Controllers\WeatherForecastController.cs" />
<Compile Remove="WeatherForecast.cs" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="ClosedXML" Version="0.105.0" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="10.0.1" />