Docker aplicado
This commit is contained in:
parent
142bb60967
commit
b924397f52
|
|
@ -0,0 +1,11 @@
|
||||||
|
.git
|
||||||
|
.github
|
||||||
|
.vs
|
||||||
|
bin
|
||||||
|
obj
|
||||||
|
**/bin
|
||||||
|
**/obj
|
||||||
|
*.user
|
||||||
|
*.suo
|
||||||
|
*.log
|
||||||
|
README.md
|
||||||
|
|
@ -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}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -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"]
|
||||||
37
Program.cs
37
Program.cs
|
|
@ -12,23 +12,34 @@ var builder = WebApplication.CreateBuilder(args);
|
||||||
|
|
||||||
builder.Services.AddControllers();
|
builder.Services.AddControllers();
|
||||||
|
|
||||||
// ✅ Upload (Excel / multipart)
|
|
||||||
builder.Services.Configure<FormOptions>(o =>
|
builder.Services.Configure<FormOptions>(o =>
|
||||||
{
|
{
|
||||||
o.MultipartBodyLengthLimit = 50_000_000;
|
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 =>
|
builder.Services.AddCors(options =>
|
||||||
{
|
{
|
||||||
options.AddPolicy("Front", p =>
|
options.AddPolicy("Front", p =>
|
||||||
p.WithOrigins("http://localhost:4200")
|
p.WithOrigins(corsOrigins)
|
||||||
.AllowAnyHeader()
|
.AllowAnyHeader()
|
||||||
.AllowAnyMethod()
|
.AllowAnyMethod()
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
// ✅ EF Core (PostgreSQL)
|
|
||||||
builder.Services.AddDbContext<AppDbContext>(options =>
|
builder.Services.AddDbContext<AppDbContext>(options =>
|
||||||
options.UseNpgsql(builder.Configuration.GetConnectionString("Default"))
|
options.UseNpgsql(builder.Configuration.GetConnectionString("Default"))
|
||||||
);
|
);
|
||||||
|
|
@ -49,12 +60,15 @@ builder.Services.AddIdentityCore<ApplicationUser>(options =>
|
||||||
.AddEntityFrameworkStores<AppDbContext>()
|
.AddEntityFrameworkStores<AppDbContext>()
|
||||||
.AddDefaultTokenProviders();
|
.AddDefaultTokenProviders();
|
||||||
|
|
||||||
// ✅ Swagger
|
|
||||||
builder.Services.AddEndpointsApiExplorer();
|
builder.Services.AddEndpointsApiExplorer();
|
||||||
builder.Services.AddSwaggerGen();
|
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 issuer = builder.Configuration["Jwt:Issuer"];
|
||||||
var audience = builder.Configuration["Jwt:Audience"];
|
var audience = builder.Configuration["Jwt:Audience"];
|
||||||
|
|
||||||
|
|
@ -89,18 +103,21 @@ if (app.Environment.IsDevelopment())
|
||||||
app.UseSwaggerUI();
|
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.UseCors("Front");
|
||||||
|
|
||||||
app.UseAuthentication();
|
app.UseAuthentication();
|
||||||
app.UseMiddleware<TenantMiddleware>();
|
app.UseMiddleware<TenantMiddleware>();
|
||||||
app.UseAuthorization();
|
app.UseAuthorization();
|
||||||
|
|
||||||
// ✅ SEED ANTES de subir controllers
|
|
||||||
await SeedData.EnsureSeedDataAsync(app.Services);
|
await SeedData.EnsureSeedDataAsync(app.Services);
|
||||||
|
|
||||||
app.MapControllers();
|
app.MapControllers();
|
||||||
|
app.MapGet("/health", () => Results.Ok(new { status = "ok" }));
|
||||||
|
|
||||||
app.Run();
|
app.Run();
|
||||||
|
|
|
||||||
|
|
@ -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; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -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": {
|
"Logging": {
|
||||||
"LogLevel": {
|
"LogLevel": {
|
||||||
"Default": "Information",
|
"Default": "Information",
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,19 @@
|
||||||
{
|
{
|
||||||
"ConnectionStrings": {
|
"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": {
|
"Jwt": {
|
||||||
"Key": "vI8/oEYEWN5sBDTisNuZFjZAl+YFvXEJ96POb73/eoq3NaFPkOFXyPRdf/HWGAFnUsF3e3QpYL6Wl4Bc2v+l3g==",
|
"Key": "",
|
||||||
"Issuer": "LineGestao",
|
"Issuer": "LineGestao",
|
||||||
"Audience": "LineGestao",
|
"Audience": "LineGestao",
|
||||||
"ExpiresMinutes": 360
|
"ExpiresMinutes": 360
|
||||||
},
|
},
|
||||||
|
"Cors": {
|
||||||
|
"AllowedOrigins": [ "http://localhost:4200" ]
|
||||||
|
},
|
||||||
|
"App": {
|
||||||
|
"UseHttpsRedirection": true
|
||||||
|
},
|
||||||
"Notifications": {
|
"Notifications": {
|
||||||
"CheckIntervalMinutes": 60,
|
"CheckIntervalMinutes": 60,
|
||||||
"ReminderDays": [30, 15, 7]
|
"ReminderDays": [30, 15, 7]
|
||||||
|
|
@ -16,6 +22,6 @@
|
||||||
"DefaultTenantName": "Default",
|
"DefaultTenantName": "Default",
|
||||||
"AdminName": "Administrador",
|
"AdminName": "Administrador",
|
||||||
"AdminEmail": "admin@linegestao.local",
|
"AdminEmail": "admin@linegestao.local",
|
||||||
"AdminPassword": "Admin123!"
|
"AdminPassword": "CHANGE_ME"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,13 +10,6 @@
|
||||||
<UseAppHost>false</UseAppHost>
|
<UseAppHost>false</UseAppHost>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<Compile Remove="NovaPasta\**" />
|
|
||||||
<Content Remove="NovaPasta\**" />
|
|
||||||
<EmbeddedResource Remove="NovaPasta\**" />
|
|
||||||
<None Remove="NovaPasta\**" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Remove="line-gestao-api.Tests\**" />
|
<Compile Remove="line-gestao-api.Tests\**" />
|
||||||
<Content Remove="line-gestao-api.Tests\**" />
|
<Content Remove="line-gestao-api.Tests\**" />
|
||||||
|
|
@ -24,11 +17,6 @@
|
||||||
<None Remove="line-gestao-api.Tests\**" />
|
<None Remove="line-gestao-api.Tests\**" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<Compile Remove="Controllers\WeatherForecastController.cs" />
|
|
||||||
<Compile Remove="WeatherForecast.cs" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="ClosedXML" Version="0.105.0" />
|
<PackageReference Include="ClosedXML" Version="0.105.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="10.0.1" />
|
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="10.0.1" />
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue