Compare commits
3 Commits
8db41acb46
...
a5c16cf881
| Author | SHA1 | Date |
|---|---|---|
|
|
a5c16cf881 | |
|
|
53665eae05 | |
|
|
1184f97a88 |
|
|
@ -1,9 +1,10 @@
|
|||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.Security.Claims;
|
||||
using System.Text;
|
||||
using line_gestao_api.Data;
|
||||
using line_gestao_api.Dtos;
|
||||
using line_gestao_api.Models;
|
||||
using line_gestao_api.Services;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
|
@ -15,80 +16,101 @@ namespace line_gestao_api.Controllers;
|
|||
[Route("auth")]
|
||||
public class AuthController : ControllerBase
|
||||
{
|
||||
private readonly AppDbContext _db;
|
||||
private readonly UserManager<ApplicationUser> _userManager;
|
||||
private readonly ITenantProvider _tenantProvider;
|
||||
private readonly IConfiguration _config;
|
||||
|
||||
public AuthController(AppDbContext db, IConfiguration config)
|
||||
public AuthController(UserManager<ApplicationUser> userManager, ITenantProvider tenantProvider, IConfiguration config)
|
||||
{
|
||||
_db = db;
|
||||
_userManager = userManager;
|
||||
_tenantProvider = tenantProvider;
|
||||
_config = config;
|
||||
}
|
||||
|
||||
[HttpPost("register")]
|
||||
[Authorize(Roles = "admin")]
|
||||
public async Task<IActionResult> Register(RegisterRequest req)
|
||||
{
|
||||
// ✅ NOVO: valida confirmação de senha (não vai pro banco, só valida)
|
||||
if (req.Password != req.ConfirmPassword)
|
||||
return BadRequest("As senhas não conferem.");
|
||||
|
||||
var email = req.Email.Trim().ToLower();
|
||||
var tenantId = _tenantProvider.TenantId;
|
||||
if (tenantId == null)
|
||||
{
|
||||
return Unauthorized("Tenant inválido.");
|
||||
}
|
||||
|
||||
var exists = await _db.Users.AnyAsync(u => u.Email.ToLower() == email);
|
||||
var email = req.Email.Trim().ToLowerInvariant();
|
||||
var normalizedEmail = _userManager.NormalizeEmail(email);
|
||||
|
||||
var exists = await _userManager.Users.AnyAsync(u => u.NormalizedEmail == normalizedEmail && u.TenantId == tenantId);
|
||||
if (exists) return BadRequest("E-mail já cadastrado.");
|
||||
|
||||
// ✅ NOVO: normaliza telefone (salva somente dígitos)
|
||||
var phoneDigits = new string((req.Phone ?? string.Empty).Where(char.IsDigit).ToArray());
|
||||
|
||||
var user = new User
|
||||
var user = new ApplicationUser
|
||||
{
|
||||
Name = req.Name.Trim(),
|
||||
Email = email,
|
||||
Phone = phoneDigits // ✅ NOVO
|
||||
UserName = email,
|
||||
TenantId = tenantId.Value,
|
||||
IsActive = true,
|
||||
EmailConfirmed = true
|
||||
};
|
||||
|
||||
var hasher = new PasswordHasher<User>();
|
||||
user.PasswordHash = hasher.HashPassword(user, req.Password);
|
||||
var createResult = await _userManager.CreateAsync(user, req.Password);
|
||||
if (!createResult.Succeeded)
|
||||
{
|
||||
return BadRequest(createResult.Errors.Select(e => e.Description).ToList());
|
||||
}
|
||||
|
||||
_db.Users.Add(user);
|
||||
await _db.SaveChangesAsync();
|
||||
await _userManager.AddToRoleAsync(user, "leitura");
|
||||
|
||||
var token = GenerateJwt(user);
|
||||
var token = await GenerateJwtAsync(user);
|
||||
return Ok(new AuthResponse(token));
|
||||
}
|
||||
|
||||
[HttpPost("login")]
|
||||
public async Task<IActionResult> Login(LoginRequest req)
|
||||
{
|
||||
var email = req.Email.Trim().ToLower();
|
||||
var email = req.Email.Trim().ToLowerInvariant();
|
||||
var normalizedEmail = _userManager.NormalizeEmail(email);
|
||||
|
||||
var user = await _db.Users.FirstOrDefaultAsync(u => u.Email.ToLower() == email);
|
||||
if (user is null) return Unauthorized("Credenciais inválidas.");
|
||||
var users = await _userManager.Users
|
||||
.Where(u => u.NormalizedEmail == normalizedEmail)
|
||||
.ToListAsync();
|
||||
|
||||
var hasher = new PasswordHasher<User>();
|
||||
var result = hasher.VerifyHashedPassword(user, user.PasswordHash, req.Password);
|
||||
|
||||
if (result == PasswordVerificationResult.Failed)
|
||||
if (users.Count != 1)
|
||||
return Unauthorized("Credenciais inválidas.");
|
||||
|
||||
var token = GenerateJwt(user);
|
||||
var user = users[0];
|
||||
if (!user.IsActive)
|
||||
return Unauthorized("Usuário desativado.");
|
||||
|
||||
var valid = await _userManager.CheckPasswordAsync(user, req.Password);
|
||||
if (!valid)
|
||||
return Unauthorized("Credenciais inválidas.");
|
||||
|
||||
var token = await GenerateJwtAsync(user);
|
||||
return Ok(new AuthResponse(token));
|
||||
}
|
||||
|
||||
private string GenerateJwt(User user)
|
||||
private async Task<string> GenerateJwtAsync(ApplicationUser user)
|
||||
{
|
||||
var key = _config["Jwt:Key"]!;
|
||||
var issuer = _config["Jwt:Issuer"]!;
|
||||
var audience = _config["Jwt:Audience"]!;
|
||||
var expiresMinutes = int.Parse(_config["Jwt:ExpiresMinutes"]!);
|
||||
|
||||
var roles = await _userManager.GetRolesAsync(user);
|
||||
var claims = new List<Claim>
|
||||
{
|
||||
new(JwtRegisteredClaimNames.Sub, user.Id.ToString()),
|
||||
new(JwtRegisteredClaimNames.Email, user.Email),
|
||||
new(JwtRegisteredClaimNames.Email, user.Email ?? string.Empty),
|
||||
new("name", user.Name),
|
||||
new("phone", user.Phone ?? string.Empty) // ✅ NOVO (opcional, mas útil)
|
||||
new("tenantId", user.TenantId.ToString())
|
||||
};
|
||||
|
||||
claims.AddRange(roles.Select(r => new Claim(ClaimTypes.Role, r)));
|
||||
|
||||
var signingKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(key));
|
||||
var creds = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256);
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,283 @@
|
|||
using line_gestao_api.Data;
|
||||
using line_gestao_api.Dtos;
|
||||
using line_gestao_api.Models;
|
||||
using line_gestao_api.Services;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace line_gestao_api.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Route("api/users")]
|
||||
[Authorize]
|
||||
public class UsersController : ControllerBase
|
||||
{
|
||||
private readonly AppDbContext _db;
|
||||
private readonly UserManager<ApplicationUser> _userManager;
|
||||
private readonly RoleManager<IdentityRole<Guid>> _roleManager;
|
||||
private readonly ITenantProvider _tenantProvider;
|
||||
|
||||
public UsersController(
|
||||
AppDbContext db,
|
||||
UserManager<ApplicationUser> userManager,
|
||||
RoleManager<IdentityRole<Guid>> roleManager,
|
||||
ITenantProvider tenantProvider)
|
||||
{
|
||||
_db = db;
|
||||
_userManager = userManager;
|
||||
_roleManager = roleManager;
|
||||
_tenantProvider = tenantProvider;
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[Authorize(Roles = "admin")]
|
||||
public async Task<ActionResult<UserListItemDto>> Create([FromBody] UserCreateRequest req)
|
||||
{
|
||||
var errors = ValidateCreate(req);
|
||||
if (errors.Count > 0)
|
||||
{
|
||||
return BadRequest(new ValidationErrorResponse { Errors = errors });
|
||||
}
|
||||
|
||||
if (_tenantProvider.TenantId == null)
|
||||
{
|
||||
return Unauthorized();
|
||||
}
|
||||
|
||||
var tenantId = _tenantProvider.TenantId.Value;
|
||||
var email = req.Email.Trim().ToLowerInvariant();
|
||||
var normalizedEmail = _userManager.NormalizeEmail(email);
|
||||
|
||||
var exists = await _userManager.Users
|
||||
.AnyAsync(u => u.TenantId == tenantId && u.NormalizedEmail == normalizedEmail);
|
||||
|
||||
if (exists)
|
||||
{
|
||||
return BadRequest(new ValidationErrorResponse
|
||||
{
|
||||
Errors = new List<ValidationErrorDto>
|
||||
{
|
||||
new() { Field = "email", Message = "E-mail já cadastrado." }
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var role = req.Permissao.Trim().ToLowerInvariant();
|
||||
if (!await _roleManager.RoleExistsAsync(role))
|
||||
{
|
||||
return BadRequest(new ValidationErrorResponse
|
||||
{
|
||||
Errors = new List<ValidationErrorDto>
|
||||
{
|
||||
new() { Field = "permissao", Message = "Permissão inválida." }
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var user = new ApplicationUser
|
||||
{
|
||||
Name = req.Nome.Trim(),
|
||||
Email = email,
|
||||
UserName = email,
|
||||
TenantId = tenantId,
|
||||
IsActive = true,
|
||||
EmailConfirmed = true
|
||||
};
|
||||
|
||||
var createResult = await _userManager.CreateAsync(user, req.Senha);
|
||||
if (!createResult.Succeeded)
|
||||
{
|
||||
return BadRequest(new ValidationErrorResponse
|
||||
{
|
||||
Errors = createResult.Errors.Select(e => new ValidationErrorDto
|
||||
{
|
||||
Field = "senha",
|
||||
Message = e.Description
|
||||
}).ToList()
|
||||
});
|
||||
}
|
||||
|
||||
await _userManager.AddToRoleAsync(user, role);
|
||||
|
||||
var response = new UserListItemDto
|
||||
{
|
||||
Id = user.Id,
|
||||
Nome = user.Name,
|
||||
Email = user.Email ?? string.Empty,
|
||||
Permissao = role,
|
||||
TenantId = user.TenantId,
|
||||
Ativo = user.IsActive
|
||||
};
|
||||
|
||||
return CreatedAtAction(nameof(GetById), new { id = user.Id }, response);
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[Authorize(Roles = "admin")]
|
||||
public async Task<ActionResult<PagedResult<UserListItemDto>>> GetAll(
|
||||
[FromQuery] string? search,
|
||||
[FromQuery] string? permissao,
|
||||
[FromQuery] int page = 1,
|
||||
[FromQuery] int pageSize = 20)
|
||||
{
|
||||
page = page < 1 ? 1 : page;
|
||||
pageSize = pageSize < 1 ? 20 : pageSize;
|
||||
|
||||
var usersQuery = _userManager.Users.AsNoTracking();
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(search))
|
||||
{
|
||||
var term = search.Trim();
|
||||
usersQuery = usersQuery.Where(u =>
|
||||
EF.Functions.ILike(u.Name, $"%{term}%") ||
|
||||
EF.Functions.ILike(u.Email ?? string.Empty, $"%{term}%"));
|
||||
}
|
||||
|
||||
IQueryable<Guid> userIdsByRole = Enumerable.Empty<Guid>().AsQueryable();
|
||||
if (!string.IsNullOrWhiteSpace(permissao))
|
||||
{
|
||||
var roleName = permissao.Trim().ToLowerInvariant();
|
||||
userIdsByRole = from ur in _db.UserRoles
|
||||
join r in _db.Roles on ur.RoleId equals r.Id
|
||||
where r.Name == roleName
|
||||
select ur.UserId;
|
||||
usersQuery = usersQuery.Where(u => userIdsByRole.Contains(u.Id));
|
||||
}
|
||||
|
||||
var total = await usersQuery.CountAsync();
|
||||
|
||||
var users = await usersQuery
|
||||
.OrderBy(u => u.Name)
|
||||
.Skip((page - 1) * pageSize)
|
||||
.Take(pageSize)
|
||||
.ToListAsync();
|
||||
|
||||
var roleLookup = await (from ur in _db.UserRoles
|
||||
join r in _db.Roles on ur.RoleId equals r.Id
|
||||
where users.Select(u => u.Id).Contains(ur.UserId)
|
||||
select new { ur.UserId, Role = r.Name ?? "" })
|
||||
.ToListAsync();
|
||||
|
||||
var roleMap = roleLookup
|
||||
.GroupBy(x => x.UserId)
|
||||
.ToDictionary(g => g.Key, g => g.First().Role);
|
||||
|
||||
var items = users.Select(u => new UserListItemDto
|
||||
{
|
||||
Id = u.Id,
|
||||
Nome = u.Name,
|
||||
Email = u.Email ?? string.Empty,
|
||||
Permissao = roleMap.GetValueOrDefault(u.Id, string.Empty),
|
||||
TenantId = u.TenantId,
|
||||
Ativo = u.IsActive
|
||||
}).ToList();
|
||||
|
||||
return Ok(new PagedResult<UserListItemDto>
|
||||
{
|
||||
Page = page,
|
||||
PageSize = pageSize,
|
||||
Total = total,
|
||||
Items = items
|
||||
});
|
||||
}
|
||||
|
||||
[HttpGet("{id:guid}")]
|
||||
[Authorize(Roles = "admin")]
|
||||
public async Task<ActionResult<UserListItemDto>> GetById(Guid id)
|
||||
{
|
||||
var user = await _userManager.Users.AsNoTracking().FirstOrDefaultAsync(u => u.Id == id);
|
||||
if (user == null)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
var roles = await _userManager.GetRolesAsync(user);
|
||||
var role = roles.FirstOrDefault() ?? string.Empty;
|
||||
|
||||
return Ok(new UserListItemDto
|
||||
{
|
||||
Id = user.Id,
|
||||
Nome = user.Name,
|
||||
Email = user.Email ?? string.Empty,
|
||||
Permissao = role,
|
||||
TenantId = user.TenantId,
|
||||
Ativo = user.IsActive
|
||||
});
|
||||
}
|
||||
|
||||
[HttpPatch("{id:guid}")]
|
||||
[Authorize(Roles = "admin")]
|
||||
public async Task<IActionResult> Update(Guid id, [FromBody] UserUpdateRequest req)
|
||||
{
|
||||
var user = await _userManager.Users.FirstOrDefaultAsync(u => u.Id == id);
|
||||
if (user == null)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
if (req.Ativo.HasValue)
|
||||
{
|
||||
user.IsActive = req.Ativo.Value;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(req.Permissao))
|
||||
{
|
||||
var roleName = req.Permissao.Trim().ToLowerInvariant();
|
||||
if (!await _roleManager.RoleExistsAsync(roleName))
|
||||
{
|
||||
return BadRequest(new ValidationErrorResponse
|
||||
{
|
||||
Errors = new List<ValidationErrorDto>
|
||||
{
|
||||
new() { Field = "permissao", Message = "Permissão inválida." }
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var existingRoles = await _userManager.GetRolesAsync(user);
|
||||
if (existingRoles.Count > 0)
|
||||
{
|
||||
await _userManager.RemoveFromRolesAsync(user, existingRoles);
|
||||
}
|
||||
|
||||
await _userManager.AddToRoleAsync(user, roleName);
|
||||
}
|
||||
|
||||
await _userManager.UpdateAsync(user);
|
||||
return NoContent();
|
||||
}
|
||||
|
||||
private static List<ValidationErrorDto> ValidateCreate(UserCreateRequest req)
|
||||
{
|
||||
var errors = new List<ValidationErrorDto>();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(req.Nome))
|
||||
{
|
||||
errors.Add(new ValidationErrorDto { Field = "nome", Message = "Nome é obrigatório." });
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(req.Email))
|
||||
{
|
||||
errors.Add(new ValidationErrorDto { Field = "email", Message = "Email é obrigatório." });
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(req.Senha) || req.Senha.Length < 6)
|
||||
{
|
||||
errors.Add(new ValidationErrorDto { Field = "senha", Message = "Senha deve ter pelo menos 6 caracteres." });
|
||||
}
|
||||
|
||||
if (req.Senha != req.ConfirmarSenha)
|
||||
{
|
||||
errors.Add(new ValidationErrorDto { Field = "confirmarSenha", Message = "Confirmação de senha inválida." });
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(req.Permissao))
|
||||
{
|
||||
errors.Add(new ValidationErrorDto { Field = "permissao", Message = "Permissão é obrigatória." });
|
||||
}
|
||||
|
||||
return errors;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,13 +1,21 @@
|
|||
using Microsoft.EntityFrameworkCore;
|
||||
using line_gestao_api.Models;
|
||||
using line_gestao_api.Models;
|
||||
using line_gestao_api.Services;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace line_gestao_api.Data;
|
||||
|
||||
public class AppDbContext : DbContext
|
||||
public class AppDbContext : IdentityDbContext<ApplicationUser, IdentityRole<Guid>, Guid>
|
||||
{
|
||||
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { }
|
||||
private readonly ITenantProvider _tenantProvider;
|
||||
|
||||
public DbSet<User> Users => Set<User>();
|
||||
public AppDbContext(DbContextOptions<AppDbContext> options, ITenantProvider tenantProvider) : base(options)
|
||||
{
|
||||
_tenantProvider = tenantProvider;
|
||||
}
|
||||
|
||||
public DbSet<Tenant> Tenants => Set<Tenant>();
|
||||
|
||||
// ✅ tabela para espelhar a planilha (GERAL)
|
||||
public DbSet<MobileLine> MobileLines => Set<MobileLine>();
|
||||
|
|
@ -35,19 +43,22 @@ public class AppDbContext : DbContext
|
|||
base.OnModelCreating(modelBuilder);
|
||||
|
||||
// =========================
|
||||
// ✅ USER
|
||||
// ✅ USER (Identity)
|
||||
// =========================
|
||||
modelBuilder.Entity<User>()
|
||||
.HasIndex(u => u.Email)
|
||||
modelBuilder.Entity<ApplicationUser>(e =>
|
||||
{
|
||||
e.Property(x => x.Name).HasMaxLength(120);
|
||||
e.HasIndex(x => new { x.TenantId, x.NormalizedEmail })
|
||||
.IsUnique();
|
||||
});
|
||||
|
||||
// =========================
|
||||
// ✅ GERAL (MobileLine)
|
||||
// =========================
|
||||
modelBuilder.Entity<MobileLine>(e =>
|
||||
{
|
||||
// Mantém UNIQUE por Linha (se Linha puder ser null no banco, Postgres aceita múltiplos nulls)
|
||||
e.HasIndex(x => x.Linha).IsUnique();
|
||||
// Mantém UNIQUE por Linha por tenant (se Linha puder ser null no banco, Postgres aceita múltiplos nulls)
|
||||
e.HasIndex(x => new { x.TenantId, x.Linha }).IsUnique();
|
||||
|
||||
// performance
|
||||
e.HasIndex(x => x.Chip);
|
||||
|
|
@ -66,6 +77,7 @@ public class AppDbContext : DbContext
|
|||
e.HasIndex(x => x.ICCID);
|
||||
e.HasIndex(x => x.LinhaAntiga);
|
||||
e.HasIndex(x => x.LinhaNova);
|
||||
e.HasIndex(x => x.TenantId);
|
||||
|
||||
// FK + index
|
||||
e.HasIndex(x => x.MobileLineId);
|
||||
|
|
@ -93,6 +105,7 @@ public class AppDbContext : DbContext
|
|||
e.HasIndex(x => x.Cliente);
|
||||
e.HasIndex(x => new { x.Tipo, x.Cliente });
|
||||
e.HasIndex(x => x.Item);
|
||||
e.HasIndex(x => x.TenantId);
|
||||
});
|
||||
|
||||
// =========================
|
||||
|
|
@ -106,6 +119,7 @@ public class AppDbContext : DbContext
|
|||
e.HasIndex(x => x.Linha);
|
||||
e.HasIndex(x => x.Cpf);
|
||||
e.HasIndex(x => x.Email);
|
||||
e.HasIndex(x => x.TenantId);
|
||||
});
|
||||
|
||||
// =========================
|
||||
|
|
@ -117,6 +131,7 @@ public class AppDbContext : DbContext
|
|||
e.HasIndex(x => x.Cliente);
|
||||
e.HasIndex(x => x.Linha);
|
||||
e.HasIndex(x => x.DtTerminoFidelizacao);
|
||||
e.HasIndex(x => x.TenantId);
|
||||
});
|
||||
|
||||
// =========================
|
||||
|
|
@ -129,6 +144,7 @@ public class AppDbContext : DbContext
|
|||
e.HasIndex(x => x.LinhaNova);
|
||||
e.HasIndex(x => x.ICCID);
|
||||
e.HasIndex(x => x.DataTroca);
|
||||
e.HasIndex(x => x.TenantId);
|
||||
});
|
||||
|
||||
// =========================
|
||||
|
|
@ -142,6 +158,7 @@ public class AppDbContext : DbContext
|
|||
e.HasIndex(x => x.Lida);
|
||||
e.HasIndex(x => x.Data);
|
||||
e.HasIndex(x => x.VigenciaLineId);
|
||||
e.HasIndex(x => x.TenantId);
|
||||
|
||||
e.HasOne(x => x.User)
|
||||
.WithMany()
|
||||
|
|
@ -153,5 +170,43 @@ public class AppDbContext : DbContext
|
|||
.HasForeignKey(x => x.VigenciaLineId)
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
});
|
||||
|
||||
modelBuilder.Entity<MobileLine>().HasQueryFilter(x => _tenantProvider.TenantId != null && x.TenantId == _tenantProvider.TenantId);
|
||||
modelBuilder.Entity<MuregLine>().HasQueryFilter(x => _tenantProvider.TenantId != null && x.TenantId == _tenantProvider.TenantId);
|
||||
modelBuilder.Entity<BillingClient>().HasQueryFilter(x => _tenantProvider.TenantId != null && x.TenantId == _tenantProvider.TenantId);
|
||||
modelBuilder.Entity<UserData>().HasQueryFilter(x => _tenantProvider.TenantId != null && x.TenantId == _tenantProvider.TenantId);
|
||||
modelBuilder.Entity<VigenciaLine>().HasQueryFilter(x => _tenantProvider.TenantId != null && x.TenantId == _tenantProvider.TenantId);
|
||||
modelBuilder.Entity<TrocaNumeroLine>().HasQueryFilter(x => _tenantProvider.TenantId != null && x.TenantId == _tenantProvider.TenantId);
|
||||
modelBuilder.Entity<Notification>().HasQueryFilter(x => _tenantProvider.TenantId != null && x.TenantId == _tenantProvider.TenantId);
|
||||
modelBuilder.Entity<ApplicationUser>().HasQueryFilter(x => _tenantProvider.TenantId != null && x.TenantId == _tenantProvider.TenantId);
|
||||
}
|
||||
|
||||
public override int SaveChanges()
|
||||
{
|
||||
ApplyTenantIds();
|
||||
return base.SaveChanges();
|
||||
}
|
||||
|
||||
public override Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
ApplyTenantIds();
|
||||
return base.SaveChangesAsync(cancellationToken);
|
||||
}
|
||||
|
||||
private void ApplyTenantIds()
|
||||
{
|
||||
if (_tenantProvider.TenantId == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var tenantId = _tenantProvider.TenantId.Value;
|
||||
foreach (var entry in ChangeTracker.Entries<ITenantEntity>().Where(e => e.State == EntityState.Added))
|
||||
{
|
||||
if (entry.Entity.TenantId == Guid.Empty)
|
||||
{
|
||||
entry.Entity.TenantId = tenantId;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,82 @@
|
|||
using line_gestao_api.Models;
|
||||
using line_gestao_api.Services;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace line_gestao_api.Data;
|
||||
|
||||
public class SeedOptions
|
||||
{
|
||||
public string DefaultTenantName { get; set; } = "Default";
|
||||
public string AdminName { get; set; } = "Administrador";
|
||||
public string AdminEmail { get; set; } = "admin@linegestao.local";
|
||||
public string AdminPassword { get; set; } = "Admin123!";
|
||||
}
|
||||
|
||||
public static class SeedData
|
||||
{
|
||||
public static readonly Guid DefaultTenantId = Guid.Parse("11111111-1111-1111-1111-111111111111");
|
||||
|
||||
public static async Task EnsureSeedDataAsync(IServiceProvider services)
|
||||
{
|
||||
using var scope = services.CreateScope();
|
||||
var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
var userManager = scope.ServiceProvider.GetRequiredService<UserManager<ApplicationUser>>();
|
||||
var roleManager = scope.ServiceProvider.GetRequiredService<RoleManager<IdentityRole<Guid>>>();
|
||||
var tenantProvider = scope.ServiceProvider.GetRequiredService<ITenantProvider>();
|
||||
var options = scope.ServiceProvider.GetRequiredService<IOptions<SeedOptions>>().Value;
|
||||
|
||||
await db.Database.MigrateAsync();
|
||||
|
||||
var roles = new[] { "admin", "gestor", "operador", "leitura" };
|
||||
foreach (var role in roles)
|
||||
{
|
||||
if (!await roleManager.RoleExistsAsync(role))
|
||||
{
|
||||
await roleManager.CreateAsync(new IdentityRole<Guid>(role));
|
||||
}
|
||||
}
|
||||
|
||||
var tenant = await db.Tenants.FirstOrDefaultAsync(t => t.Id == DefaultTenantId);
|
||||
if (tenant == null)
|
||||
{
|
||||
tenant = new Tenant
|
||||
{
|
||||
Id = DefaultTenantId,
|
||||
Name = options.DefaultTenantName,
|
||||
CreatedAt = DateTime.UtcNow
|
||||
};
|
||||
|
||||
db.Tenants.Add(tenant);
|
||||
await db.SaveChangesAsync();
|
||||
}
|
||||
|
||||
tenantProvider.SetTenantId(tenant.Id);
|
||||
|
||||
var normalizedEmail = userManager.NormalizeEmail(options.AdminEmail);
|
||||
var existingAdmin = await userManager.Users
|
||||
.FirstOrDefaultAsync(u => u.NormalizedEmail == normalizedEmail && u.TenantId == tenant.Id);
|
||||
|
||||
if (existingAdmin == null)
|
||||
{
|
||||
var adminUser = new ApplicationUser
|
||||
{
|
||||
UserName = options.AdminEmail,
|
||||
Email = options.AdminEmail,
|
||||
Name = options.AdminName,
|
||||
TenantId = tenant.Id,
|
||||
EmailConfirmed = true,
|
||||
IsActive = true
|
||||
};
|
||||
|
||||
var createResult = await userManager.CreateAsync(adminUser, options.AdminPassword);
|
||||
if (createResult.Succeeded)
|
||||
{
|
||||
await userManager.AddToRoleAsync(adminUser, "admin");
|
||||
}
|
||||
}
|
||||
|
||||
tenantProvider.SetTenantId(null);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
namespace line_gestao_api.Dtos;
|
||||
|
||||
public class UserCreateRequest
|
||||
{
|
||||
public string Nome { get; set; } = string.Empty;
|
||||
public string Email { get; set; } = string.Empty;
|
||||
public string Senha { get; set; } = string.Empty;
|
||||
public string ConfirmarSenha { get; set; } = string.Empty;
|
||||
public string Permissao { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
public class UserUpdateRequest
|
||||
{
|
||||
public string? Permissao { get; set; }
|
||||
public bool? Ativo { get; set; }
|
||||
}
|
||||
|
||||
public class UserListItemDto
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
public string Nome { get; set; } = string.Empty;
|
||||
public string Email { get; set; } = string.Empty;
|
||||
public string Permissao { get; set; } = string.Empty;
|
||||
public Guid TenantId { get; set; }
|
||||
public bool Ativo { get; set; }
|
||||
}
|
||||
|
||||
public class ValidationErrorDto
|
||||
{
|
||||
public string Field { get; set; } = string.Empty;
|
||||
public string Message { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
public class ValidationErrorResponse
|
||||
{
|
||||
public List<ValidationErrorDto> Errors { get; set; } = new();
|
||||
}
|
||||
|
|
@ -0,0 +1,837 @@
|
|||
// <auto-generated />
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||
using line_gestao_api.Data;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace line_gestao_api.Migrations
|
||||
{
|
||||
[DbContext(typeof(AppDbContext))]
|
||||
[Migration("20260210120000_AddIdentityAndTenants")]
|
||||
partial class AddIdentityAndTenants
|
||||
{
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "10.0.1")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
||||
|
||||
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||
|
||||
modelBuilder.Entity("line_gestao_api.Models.ApplicationUser", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<int>("AccessFailedCount")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<string>("ConcurrencyStamp")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<string>("Email")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("character varying(256)");
|
||||
|
||||
b.Property<bool>("EmailConfirmed")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.Property<bool>("IsActive")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.Property<DateTimeOffset?>("LockoutEnd")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<bool>("LockoutEnabled")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(120)
|
||||
.HasColumnType("character varying(120)");
|
||||
|
||||
b.Property<string>("NormalizedEmail")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("character varying(256)");
|
||||
|
||||
b.Property<string>("NormalizedUserName")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("character varying(256)");
|
||||
|
||||
b.Property<string>("PasswordHash")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("PhoneNumber")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<bool>("PhoneNumberConfirmed")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.Property<string>("SecurityStamp")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<Guid>("TenantId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<bool>("TwoFactorEnabled")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.Property<string>("UserName")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("character varying(256)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NormalizedEmail");
|
||||
|
||||
b.HasIndex("NormalizedUserName")
|
||||
.IsUnique();
|
||||
|
||||
b.HasIndex("TenantId", "NormalizedEmail")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("AspNetUsers", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("line_gestao_api.Models.BillingClient", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<string>("Aparelho")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Cliente")
|
||||
.IsRequired()
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("character varying(255)");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<string>("FormaPagamento")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<decimal?>("FranquiaLine")
|
||||
.HasColumnType("numeric");
|
||||
|
||||
b.Property<decimal?>("FranquiaVivo")
|
||||
.HasColumnType("numeric");
|
||||
|
||||
b.Property<int>("Item")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<decimal?>("Lucro")
|
||||
.HasColumnType("numeric");
|
||||
|
||||
b.Property<int?>("QtdLinhas")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<Guid>("TenantId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<string>("Tipo")
|
||||
.IsRequired()
|
||||
.HasMaxLength(2)
|
||||
.HasColumnType("character varying(2)");
|
||||
|
||||
b.Property<DateTime>("UpdatedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<decimal?>("ValorContratoLine")
|
||||
.HasColumnType("numeric");
|
||||
|
||||
b.Property<decimal?>("ValorContratoVivo")
|
||||
.HasColumnType("numeric");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("Cliente");
|
||||
|
||||
b.HasIndex("Item");
|
||||
|
||||
b.HasIndex("TenantId");
|
||||
|
||||
b.HasIndex("Tipo");
|
||||
|
||||
b.HasIndex("Tipo", "Cliente");
|
||||
|
||||
b.ToTable("billing_clients", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("line_gestao_api.Models.MobileLine", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<string>("Cedente")
|
||||
.HasMaxLength(150)
|
||||
.HasColumnType("character varying(150)");
|
||||
|
||||
b.Property<string>("Chip")
|
||||
.HasMaxLength(40)
|
||||
.HasColumnType("character varying(40)");
|
||||
|
||||
b.Property<string>("Cliente")
|
||||
.HasMaxLength(200)
|
||||
.HasColumnType("character varying(200)");
|
||||
|
||||
b.Property<string>("Conta")
|
||||
.HasMaxLength(80)
|
||||
.HasColumnType("character varying(80)");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<DateTime?>("DataBloqueio")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<DateTime?>("DataEntregaCliente")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<DateTime?>("DataEntregaOpera")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<decimal?>("Desconto")
|
||||
.HasColumnType("numeric");
|
||||
|
||||
b.Property<decimal?>("FranquiaGestao")
|
||||
.HasColumnType("numeric");
|
||||
|
||||
b.Property<decimal?>("FranquiaLine")
|
||||
.HasColumnType("numeric");
|
||||
|
||||
b.Property<decimal?>("FranquiaVivo")
|
||||
.HasColumnType("numeric");
|
||||
|
||||
b.Property<decimal?>("GestaoVozDados")
|
||||
.HasColumnType("numeric");
|
||||
|
||||
b.Property<int>("Item")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<string>("Linha")
|
||||
.HasMaxLength(30)
|
||||
.HasColumnType("character varying(30)");
|
||||
|
||||
b.Property<decimal?>("LocacaoAp")
|
||||
.HasColumnType("numeric");
|
||||
|
||||
b.Property<decimal?>("Lucro")
|
||||
.HasColumnType("numeric");
|
||||
|
||||
b.Property<string>("Modalidade")
|
||||
.HasMaxLength(80)
|
||||
.HasColumnType("character varying(80)");
|
||||
|
||||
b.Property<string>("PlanoContrato")
|
||||
.HasMaxLength(200)
|
||||
.HasColumnType("character varying(200)");
|
||||
|
||||
b.Property<decimal?>("Skeelo")
|
||||
.HasColumnType("numeric");
|
||||
|
||||
b.Property<string>("Skil")
|
||||
.HasMaxLength(80)
|
||||
.HasColumnType("character varying(80)");
|
||||
|
||||
b.Property<string>("Solicitante")
|
||||
.HasMaxLength(150)
|
||||
.HasColumnType("character varying(150)");
|
||||
|
||||
b.Property<string>("Status")
|
||||
.HasMaxLength(80)
|
||||
.HasColumnType("character varying(80)");
|
||||
|
||||
b.Property<Guid>("TenantId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<DateTime>("UpdatedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<string>("Usuario")
|
||||
.HasMaxLength(200)
|
||||
.HasColumnType("character varying(200)");
|
||||
|
||||
b.Property<decimal?>("ValorContratoLine")
|
||||
.HasColumnType("numeric");
|
||||
|
||||
b.Property<decimal?>("ValorContratoVivo")
|
||||
.HasColumnType("numeric");
|
||||
|
||||
b.Property<decimal?>("ValorPlanoVivo")
|
||||
.HasColumnType("numeric");
|
||||
|
||||
b.Property<string>("VencConta")
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("character varying(50)");
|
||||
|
||||
b.Property<decimal?>("VivoGestaoDispositivo")
|
||||
.HasColumnType("numeric");
|
||||
|
||||
b.Property<decimal?>("VivoNewsPlus")
|
||||
.HasColumnType("numeric");
|
||||
|
||||
b.Property<decimal?>("VivoTravelMundo")
|
||||
.HasColumnType("numeric");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("Chip");
|
||||
|
||||
b.HasIndex("Cliente");
|
||||
|
||||
b.HasIndex("Skil");
|
||||
|
||||
b.HasIndex("Status");
|
||||
|
||||
b.HasIndex("TenantId", "Linha")
|
||||
.IsUnique();
|
||||
|
||||
b.HasIndex("Usuario");
|
||||
|
||||
b.ToTable("MobileLines");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("line_gestao_api.Models.MuregLine", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<DateTime?>("DataDaMureg")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<string>("ICCID")
|
||||
.HasMaxLength(40)
|
||||
.HasColumnType("character varying(40)");
|
||||
|
||||
b.Property<int>("Item")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<string>("LinhaAntiga")
|
||||
.HasMaxLength(30)
|
||||
.HasColumnType("character varying(30)");
|
||||
|
||||
b.Property<string>("LinhaNova")
|
||||
.HasMaxLength(30)
|
||||
.HasColumnType("character varying(30)");
|
||||
|
||||
b.Property<Guid>("MobileLineId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<Guid>("TenantId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<DateTime>("UpdatedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ICCID");
|
||||
|
||||
b.HasIndex("Item");
|
||||
|
||||
b.HasIndex("LinhaAntiga");
|
||||
|
||||
b.HasIndex("LinhaNova");
|
||||
|
||||
b.HasIndex("MobileLineId");
|
||||
|
||||
b.HasIndex("TenantId");
|
||||
|
||||
b.ToTable("MuregLines");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("line_gestao_api.Models.Notification", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<string>("Cliente")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<DateTime>("Data")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<string>("DedupKey")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<int?>("DiasParaVencer")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<string>("Linha")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<bool>("Lida")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.Property<DateTime?>("LidaEm")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<string>("Mensagem")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<DateTime?>("ReferenciaData")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<Guid>("TenantId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<string>("Tipo")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Titulo")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<Guid?>("UserId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<string>("Usuario")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<Guid?>("VigenciaLineId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("Cliente");
|
||||
|
||||
b.HasIndex("Data");
|
||||
|
||||
b.HasIndex("DedupKey")
|
||||
.IsUnique();
|
||||
|
||||
b.HasIndex("Lida");
|
||||
|
||||
b.HasIndex("TenantId");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.HasIndex("VigenciaLineId");
|
||||
|
||||
b.ToTable("Notifications");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("line_gestao_api.Models.Tenant", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Tenants");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("line_gestao_api.Models.TrocaNumeroLine", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<DateTime?>("DataTroca")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<string>("ICCID")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<int>("Item")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<string>("LinhaAntiga")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("LinhaNova")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Motivo")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Observacao")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<Guid>("TenantId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<DateTime>("UpdatedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("DataTroca");
|
||||
|
||||
b.HasIndex("ICCID");
|
||||
|
||||
b.HasIndex("Item");
|
||||
|
||||
b.HasIndex("LinhaAntiga");
|
||||
|
||||
b.HasIndex("LinhaNova");
|
||||
|
||||
b.HasIndex("TenantId");
|
||||
|
||||
b.ToTable("TrocaNumeroLines");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("line_gestao_api.Models.UserData", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<string>("Celular")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Cliente")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Cpf")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<DateTime?>("DataNascimento")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<string>("Email")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Endereco")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<int>("Item")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<string>("Linha")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Rg")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<Guid>("TenantId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<string>("TelefoneFixo")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<DateTime>("UpdatedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("Cliente");
|
||||
|
||||
b.HasIndex("Cpf");
|
||||
|
||||
b.HasIndex("Email");
|
||||
|
||||
b.HasIndex("Item");
|
||||
|
||||
b.HasIndex("Linha");
|
||||
|
||||
b.HasIndex("TenantId");
|
||||
|
||||
b.ToTable("UserDatas");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("line_gestao_api.Models.VigenciaLine", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<string>("Cliente")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Conta")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<DateTime?>("DtEfetivacaoServico")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<DateTime?>("DtTerminoFidelizacao")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<int>("Item")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<string>("Linha")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("PlanoContrato")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<Guid>("TenantId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<decimal?>("Total")
|
||||
.HasColumnType("numeric");
|
||||
|
||||
b.Property<DateTime>("UpdatedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<string>("Usuario")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("Cliente");
|
||||
|
||||
b.HasIndex("DtTerminoFidelizacao");
|
||||
|
||||
b.HasIndex("Item");
|
||||
|
||||
b.HasIndex("Linha");
|
||||
|
||||
b.HasIndex("TenantId");
|
||||
|
||||
b.ToTable("VigenciaLines");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole<Guid>", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<string>("ConcurrencyStamp")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("character varying(256)");
|
||||
|
||||
b.Property<string>("NormalizedName")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("character varying(256)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NormalizedName")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("AspNetRoles", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<Guid>", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("integer")
|
||||
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
||||
|
||||
b.Property<string>("ClaimType")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("ClaimValue")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<Guid>("RoleId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("RoleId");
|
||||
|
||||
b.ToTable("AspNetRoleClaims", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<Guid>", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("integer")
|
||||
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
||||
|
||||
b.Property<string>("ClaimType")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("ClaimValue")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<Guid>("UserId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("AspNetUserClaims", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<Guid>", b =>
|
||||
{
|
||||
b.Property<string>("LoginProvider")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("ProviderKey")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("ProviderDisplayName")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<Guid>("UserId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.HasKey("LoginProvider", "ProviderKey");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("AspNetUserLogins", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<Guid>", b =>
|
||||
{
|
||||
b.Property<Guid>("UserId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<Guid>("RoleId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.HasKey("UserId", "RoleId");
|
||||
|
||||
b.HasIndex("RoleId");
|
||||
|
||||
b.ToTable("AspNetUserRoles", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<Guid>", b =>
|
||||
{
|
||||
b.Property<Guid>("UserId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<string>("LoginProvider")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Value")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("UserId", "LoginProvider", "Name");
|
||||
|
||||
b.ToTable("AspNetUserTokens", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("line_gestao_api.Models.MuregLine", b =>
|
||||
{
|
||||
b.HasOne("line_gestao_api.Models.MobileLine", "MobileLine")
|
||||
.WithMany("Muregs")
|
||||
.HasForeignKey("MobileLineId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("MobileLine");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("line_gestao_api.Models.Notification", b =>
|
||||
{
|
||||
b.HasOne("line_gestao_api.Models.ApplicationUser", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
b.HasOne("line_gestao_api.Models.VigenciaLine", "VigenciaLine")
|
||||
.WithMany()
|
||||
.HasForeignKey("VigenciaLineId")
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
b.Navigation("User");
|
||||
|
||||
b.Navigation("VigenciaLine");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<Guid>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole<Guid>", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("RoleId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<Guid>", b =>
|
||||
{
|
||||
b.HasOne("line_gestao_api.Models.ApplicationUser", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<Guid>", b =>
|
||||
{
|
||||
b.HasOne("line_gestao_api.Models.ApplicationUser", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<Guid>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole<Guid>", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("RoleId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("line_gestao_api.Models.ApplicationUser", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<Guid>", b =>
|
||||
{
|
||||
b.HasOne("line_gestao_api.Models.ApplicationUser", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("line_gestao_api.Models.MobileLine", b =>
|
||||
{
|
||||
b.Navigation("Muregs");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,456 @@
|
|||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace line_gestao_api.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class AddIdentityAndTenants : Migration
|
||||
{
|
||||
private static readonly Guid DefaultTenantId = Guid.Parse("11111111-1111-1111-1111-111111111111");
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_Notifications_Users_UserId",
|
||||
table: "Notifications");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "Users");
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "Tenants",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
Name = table.Column<string>(type: "text", nullable: false),
|
||||
CreatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_Tenants", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "AspNetRoles",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
Name = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
|
||||
NormalizedName = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
|
||||
ConcurrencyStamp = table.Column<string>(type: "text", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_AspNetRoles", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "AspNetUsers",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
Name = table.Column<string>(type: "character varying(120)", maxLength: 120, nullable: false),
|
||||
TenantId = table.Column<Guid>(type: "uuid", nullable: false, defaultValue: DefaultTenantId),
|
||||
IsActive = table.Column<bool>(type: "boolean", nullable: false, defaultValue: true),
|
||||
CreatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
|
||||
UserName = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
|
||||
NormalizedUserName = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
|
||||
Email = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
|
||||
NormalizedEmail = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
|
||||
EmailConfirmed = table.Column<bool>(type: "boolean", nullable: false),
|
||||
PasswordHash = table.Column<string>(type: "text", nullable: true),
|
||||
SecurityStamp = table.Column<string>(type: "text", nullable: true),
|
||||
ConcurrencyStamp = table.Column<string>(type: "text", nullable: true),
|
||||
PhoneNumber = table.Column<string>(type: "text", nullable: true),
|
||||
PhoneNumberConfirmed = table.Column<bool>(type: "boolean", nullable: false),
|
||||
TwoFactorEnabled = table.Column<bool>(type: "boolean", nullable: false),
|
||||
LockoutEnd = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: true),
|
||||
LockoutEnabled = table.Column<bool>(type: "boolean", nullable: false),
|
||||
AccessFailedCount = table.Column<int>(type: "integer", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_AspNetUsers", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "AspNetRoleClaims",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "integer", nullable: false)
|
||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||
RoleId = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
ClaimType = table.Column<string>(type: "text", nullable: true),
|
||||
ClaimValue = table.Column<string>(type: "text", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_AspNetRoleClaims", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_AspNetRoleClaims_AspNetRoles_RoleId",
|
||||
column: x => x.RoleId,
|
||||
principalTable: "AspNetRoles",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "AspNetUserClaims",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "integer", nullable: false)
|
||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||
UserId = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
ClaimType = table.Column<string>(type: "text", nullable: true),
|
||||
ClaimValue = table.Column<string>(type: "text", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_AspNetUserClaims", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_AspNetUserClaims_AspNetUsers_UserId",
|
||||
column: x => x.UserId,
|
||||
principalTable: "AspNetUsers",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "AspNetUserLogins",
|
||||
columns: table => new
|
||||
{
|
||||
LoginProvider = table.Column<string>(type: "text", nullable: false),
|
||||
ProviderKey = table.Column<string>(type: "text", nullable: false),
|
||||
ProviderDisplayName = table.Column<string>(type: "text", nullable: true),
|
||||
UserId = table.Column<Guid>(type: "uuid", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_AspNetUserLogins", x => new { x.LoginProvider, x.ProviderKey });
|
||||
table.ForeignKey(
|
||||
name: "FK_AspNetUserLogins_AspNetUsers_UserId",
|
||||
column: x => x.UserId,
|
||||
principalTable: "AspNetUsers",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "AspNetUserRoles",
|
||||
columns: table => new
|
||||
{
|
||||
UserId = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
RoleId = table.Column<Guid>(type: "uuid", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_AspNetUserRoles", x => new { x.UserId, x.RoleId });
|
||||
table.ForeignKey(
|
||||
name: "FK_AspNetUserRoles_AspNetRoles_RoleId",
|
||||
column: x => x.RoleId,
|
||||
principalTable: "AspNetRoles",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
table.ForeignKey(
|
||||
name: "FK_AspNetUserRoles_AspNetUsers_UserId",
|
||||
column: x => x.UserId,
|
||||
principalTable: "AspNetUsers",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "AspNetUserTokens",
|
||||
columns: table => new
|
||||
{
|
||||
UserId = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
LoginProvider = table.Column<string>(type: "text", nullable: false),
|
||||
Name = table.Column<string>(type: "text", nullable: false),
|
||||
Value = table.Column<string>(type: "text", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_AspNetUserTokens", x => new { x.UserId, x.LoginProvider, x.Name });
|
||||
table.ForeignKey(
|
||||
name: "FK_AspNetUserTokens_AspNetUsers_UserId",
|
||||
column: x => x.UserId,
|
||||
principalTable: "AspNetUsers",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.AddColumn<Guid>(
|
||||
name: "TenantId",
|
||||
table: "MobileLines",
|
||||
type: "uuid",
|
||||
nullable: false,
|
||||
defaultValue: DefaultTenantId);
|
||||
|
||||
migrationBuilder.AddColumn<Guid>(
|
||||
name: "TenantId",
|
||||
table: "MuregLines",
|
||||
type: "uuid",
|
||||
nullable: false,
|
||||
defaultValue: DefaultTenantId);
|
||||
|
||||
migrationBuilder.AddColumn<Guid>(
|
||||
name: "TenantId",
|
||||
table: "billing_clients",
|
||||
type: "uuid",
|
||||
nullable: false,
|
||||
defaultValue: DefaultTenantId);
|
||||
|
||||
migrationBuilder.AddColumn<Guid>(
|
||||
name: "TenantId",
|
||||
table: "UserDatas",
|
||||
type: "uuid",
|
||||
nullable: false,
|
||||
defaultValue: DefaultTenantId);
|
||||
|
||||
migrationBuilder.AddColumn<Guid>(
|
||||
name: "TenantId",
|
||||
table: "VigenciaLines",
|
||||
type: "uuid",
|
||||
nullable: false,
|
||||
defaultValue: DefaultTenantId);
|
||||
|
||||
migrationBuilder.AddColumn<Guid>(
|
||||
name: "TenantId",
|
||||
table: "TrocaNumeroLines",
|
||||
type: "uuid",
|
||||
nullable: false,
|
||||
defaultValue: DefaultTenantId);
|
||||
|
||||
migrationBuilder.AddColumn<Guid>(
|
||||
name: "TenantId",
|
||||
table: "Notifications",
|
||||
type: "uuid",
|
||||
nullable: false,
|
||||
defaultValue: DefaultTenantId);
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_MobileLines_Linha",
|
||||
table: "MobileLines");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_MobileLines_TenantId_Linha",
|
||||
table: "MobileLines",
|
||||
columns: new[] { "TenantId", "Linha" },
|
||||
unique: true);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_MuregLines_TenantId",
|
||||
table: "MuregLines",
|
||||
column: "TenantId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_billing_clients_TenantId",
|
||||
table: "billing_clients",
|
||||
column: "TenantId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_UserDatas_TenantId",
|
||||
table: "UserDatas",
|
||||
column: "TenantId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_VigenciaLines_TenantId",
|
||||
table: "VigenciaLines",
|
||||
column: "TenantId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_TrocaNumeroLines_TenantId",
|
||||
table: "TrocaNumeroLines",
|
||||
column: "TenantId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Notifications_TenantId",
|
||||
table: "Notifications",
|
||||
column: "TenantId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_AspNetRoles_NormalizedName",
|
||||
table: "AspNetRoles",
|
||||
column: "NormalizedName",
|
||||
unique: true);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_AspNetUsers_NormalizedEmail",
|
||||
table: "AspNetUsers",
|
||||
column: "NormalizedEmail");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_AspNetUsers_NormalizedUserName",
|
||||
table: "AspNetUsers",
|
||||
column: "NormalizedUserName",
|
||||
unique: true);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_AspNetUsers_TenantId_NormalizedEmail",
|
||||
table: "AspNetUsers",
|
||||
columns: new[] { "TenantId", "NormalizedEmail" },
|
||||
unique: true);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_AspNetRoleClaims_RoleId",
|
||||
table: "AspNetRoleClaims",
|
||||
column: "RoleId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_AspNetUserClaims_UserId",
|
||||
table: "AspNetUserClaims",
|
||||
column: "UserId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_AspNetUserLogins_UserId",
|
||||
table: "AspNetUserLogins",
|
||||
column: "UserId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_AspNetUserRoles_RoleId",
|
||||
table: "AspNetUserRoles",
|
||||
column: "RoleId");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_Notifications_AspNetUsers_UserId",
|
||||
table: "Notifications",
|
||||
column: "UserId",
|
||||
principalTable: "AspNetUsers",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Restrict);
|
||||
|
||||
migrationBuilder.InsertData(
|
||||
table: "Tenants",
|
||||
columns: new[] { "Id", "Name", "CreatedAt" },
|
||||
values: new object[] { DefaultTenantId, "Default", DateTime.UtcNow });
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_Notifications_AspNetUsers_UserId",
|
||||
table: "Notifications");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "AspNetRoleClaims");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "AspNetUserClaims");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "AspNetUserLogins");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "AspNetUserRoles");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "AspNetUserTokens");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "AspNetRoles");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "AspNetUsers");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "Tenants");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_MobileLines_TenantId_Linha",
|
||||
table: "MobileLines");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_MuregLines_TenantId",
|
||||
table: "MuregLines");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_billing_clients_TenantId",
|
||||
table: "billing_clients");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_UserDatas_TenantId",
|
||||
table: "UserDatas");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_VigenciaLines_TenantId",
|
||||
table: "VigenciaLines");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_TrocaNumeroLines_TenantId",
|
||||
table: "TrocaNumeroLines");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_Notifications_TenantId",
|
||||
table: "Notifications");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "TenantId",
|
||||
table: "MobileLines");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "TenantId",
|
||||
table: "MuregLines");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "TenantId",
|
||||
table: "billing_clients");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "TenantId",
|
||||
table: "UserDatas");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "TenantId",
|
||||
table: "VigenciaLines");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "TenantId",
|
||||
table: "TrocaNumeroLines");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "TenantId",
|
||||
table: "Notifications");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_MobileLines_Linha",
|
||||
table: "MobileLines",
|
||||
column: "Linha",
|
||||
unique: true);
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "Users",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
Name = table.Column<string>(type: "character varying(120)", maxLength: 120, nullable: false),
|
||||
Email = table.Column<string>(type: "character varying(120)", maxLength: 120, nullable: false),
|
||||
Phone = table.Column<string>(type: "character varying(20)", maxLength: 20, nullable: false),
|
||||
PasswordHash = table.Column<string>(type: "text", nullable: false),
|
||||
CreatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_Users", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Users_Email",
|
||||
table: "Users",
|
||||
column: "Email",
|
||||
unique: true);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_Notifications_Users_UserId",
|
||||
table: "Notifications",
|
||||
column: "UserId",
|
||||
principalTable: "Users",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Restrict);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace line_gestao_api.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class RenameUserNameIndexSafe : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.Sql("ALTER INDEX IF EXISTS \"IX_AspNetUsers_NormalizedUserName\" RENAME TO \"UserNameIndex\"");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.Sql("ALTER INDEX IF EXISTS \"UserNameIndex\" RENAME TO \"IX_AspNetUsers_NormalizedUserName\"");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
// <auto-generated />
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
|
|
@ -22,6 +22,85 @@ namespace line_gestao_api.Migrations
|
|||
|
||||
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||
|
||||
modelBuilder.Entity("line_gestao_api.Models.ApplicationUser", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<int>("AccessFailedCount")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<string>("ConcurrencyStamp")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<string>("Email")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("character varying(256)");
|
||||
|
||||
b.Property<bool>("EmailConfirmed")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.Property<bool>("IsActive")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.Property<DateTimeOffset?>("LockoutEnd")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<bool>("LockoutEnabled")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(120)
|
||||
.HasColumnType("character varying(120)");
|
||||
|
||||
b.Property<string>("NormalizedEmail")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("character varying(256)");
|
||||
|
||||
b.Property<string>("NormalizedUserName")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("character varying(256)");
|
||||
|
||||
b.Property<string>("PasswordHash")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("PhoneNumber")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<bool>("PhoneNumberConfirmed")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.Property<string>("SecurityStamp")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<Guid>("TenantId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<bool>("TwoFactorEnabled")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.Property<string>("UserName")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("character varying(256)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NormalizedEmail");
|
||||
|
||||
b.HasIndex("NormalizedUserName")
|
||||
.IsUnique();
|
||||
|
||||
b.HasIndex("TenantId", "NormalizedEmail")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("AspNetUsers", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("line_gestao_api.Models.BillingClient", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
|
|
@ -57,6 +136,9 @@ namespace line_gestao_api.Migrations
|
|||
b.Property<int?>("QtdLinhas")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<Guid>("TenantId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<string>("Tipo")
|
||||
.IsRequired()
|
||||
.HasMaxLength(2)
|
||||
|
|
@ -77,6 +159,8 @@ namespace line_gestao_api.Migrations
|
|||
|
||||
b.HasIndex("Item");
|
||||
|
||||
b.HasIndex("TenantId");
|
||||
|
||||
b.HasIndex("Tipo");
|
||||
|
||||
b.HasIndex("Tipo", "Cliente");
|
||||
|
|
@ -169,6 +253,9 @@ namespace line_gestao_api.Migrations
|
|||
.HasMaxLength(80)
|
||||
.HasColumnType("character varying(80)");
|
||||
|
||||
b.Property<Guid>("TenantId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<DateTime>("UpdatedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
|
|
@ -204,13 +291,13 @@ namespace line_gestao_api.Migrations
|
|||
|
||||
b.HasIndex("Cliente");
|
||||
|
||||
b.HasIndex("Linha")
|
||||
.IsUnique();
|
||||
|
||||
b.HasIndex("Skil");
|
||||
|
||||
b.HasIndex("Status");
|
||||
|
||||
b.HasIndex("TenantId", "Linha")
|
||||
.IsUnique();
|
||||
|
||||
b.HasIndex("Usuario");
|
||||
|
||||
b.ToTable("MobileLines");
|
||||
|
|
@ -246,6 +333,9 @@ namespace line_gestao_api.Migrations
|
|||
b.Property<Guid>("MobileLineId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<Guid>("TenantId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<DateTime>("UpdatedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
|
|
@ -261,93 +351,11 @@ namespace line_gestao_api.Migrations
|
|||
|
||||
b.HasIndex("MobileLineId");
|
||||
|
||||
b.HasIndex("TenantId");
|
||||
|
||||
b.ToTable("MuregLines");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("line_gestao_api.Models.TrocaNumeroLine", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<DateTime?>("DataTroca")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<string>("ICCID")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<int>("Item")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<string>("LinhaAntiga")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("LinhaNova")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Motivo")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Observacao")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<DateTime>("UpdatedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("DataTroca");
|
||||
|
||||
b.HasIndex("ICCID");
|
||||
|
||||
b.HasIndex("Item");
|
||||
|
||||
b.HasIndex("LinhaAntiga");
|
||||
|
||||
b.HasIndex("LinhaNova");
|
||||
|
||||
b.ToTable("TrocaNumeroLines");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("line_gestao_api.Models.User", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<string>("Email")
|
||||
.IsRequired()
|
||||
.HasMaxLength(120)
|
||||
.HasColumnType("character varying(120)");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(120)
|
||||
.HasColumnType("character varying(120)");
|
||||
|
||||
b.Property<string>("PasswordHash")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Phone")
|
||||
.IsRequired()
|
||||
.HasMaxLength(20)
|
||||
.HasColumnType("character varying(20)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("Email")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("Users");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("line_gestao_api.Models.Notification", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
|
|
@ -383,6 +391,9 @@ namespace line_gestao_api.Migrations
|
|||
b.Property<DateTime?>("ReferenciaData")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<Guid>("TenantId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<string>("Tipo")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
|
@ -411,6 +422,8 @@ namespace line_gestao_api.Migrations
|
|||
|
||||
b.HasIndex("Lida");
|
||||
|
||||
b.HasIndex("TenantId");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.HasIndex("VigenciaLineId");
|
||||
|
|
@ -418,6 +431,76 @@ namespace line_gestao_api.Migrations
|
|||
b.ToTable("Notifications");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("line_gestao_api.Models.Tenant", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Tenants");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("line_gestao_api.Models.TrocaNumeroLine", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<DateTime?>("DataTroca")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<string>("ICCID")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<int>("Item")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<string>("LinhaAntiga")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("LinhaNova")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Motivo")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Observacao")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<Guid>("TenantId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<DateTime>("UpdatedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("DataTroca");
|
||||
|
||||
b.HasIndex("ICCID");
|
||||
|
||||
b.HasIndex("Item");
|
||||
|
||||
b.HasIndex("LinhaAntiga");
|
||||
|
||||
b.HasIndex("LinhaNova");
|
||||
|
||||
b.HasIndex("TenantId");
|
||||
|
||||
b.ToTable("TrocaNumeroLines");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("line_gestao_api.Models.UserData", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
|
|
@ -454,6 +537,9 @@ namespace line_gestao_api.Migrations
|
|||
b.Property<string>("Rg")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<Guid>("TenantId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<string>("TelefoneFixo")
|
||||
.HasColumnType("text");
|
||||
|
||||
|
|
@ -472,6 +558,8 @@ namespace line_gestao_api.Migrations
|
|||
|
||||
b.HasIndex("Linha");
|
||||
|
||||
b.HasIndex("TenantId");
|
||||
|
||||
b.ToTable("UserDatas");
|
||||
});
|
||||
|
||||
|
|
@ -505,6 +593,9 @@ namespace line_gestao_api.Migrations
|
|||
b.Property<string>("PlanoContrato")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<Guid>("TenantId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<decimal?>("Total")
|
||||
.HasColumnType("numeric");
|
||||
|
||||
|
|
@ -524,12 +615,151 @@ namespace line_gestao_api.Migrations
|
|||
|
||||
b.HasIndex("Linha");
|
||||
|
||||
b.HasIndex("TenantId");
|
||||
|
||||
b.ToTable("VigenciaLines");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole<Guid>", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<string>("ConcurrencyStamp")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("character varying(256)");
|
||||
|
||||
b.Property<string>("NormalizedName")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("character varying(256)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NormalizedName")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("AspNetRoles", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<Guid>", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("integer")
|
||||
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
||||
|
||||
b.Property<string>("ClaimType")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("ClaimValue")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<Guid>("RoleId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("RoleId");
|
||||
|
||||
b.ToTable("AspNetRoleClaims", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<Guid>", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("integer")
|
||||
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
||||
|
||||
b.Property<string>("ClaimType")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("ClaimValue")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<Guid>("UserId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("AspNetUserClaims", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<Guid>", b =>
|
||||
{
|
||||
b.Property<string>("LoginProvider")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("ProviderKey")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("ProviderDisplayName")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<Guid>("UserId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.HasKey("LoginProvider", "ProviderKey");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("AspNetUserLogins", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<Guid>", b =>
|
||||
{
|
||||
b.Property<Guid>("UserId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<Guid>("RoleId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.HasKey("UserId", "RoleId");
|
||||
|
||||
b.HasIndex("RoleId");
|
||||
|
||||
b.ToTable("AspNetUserRoles", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<Guid>", b =>
|
||||
{
|
||||
b.Property<Guid>("UserId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<string>("LoginProvider")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Value")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("UserId", "LoginProvider", "Name");
|
||||
|
||||
b.ToTable("AspNetUserTokens", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("line_gestao_api.Models.MuregLine", b =>
|
||||
{
|
||||
b.HasOne("line_gestao_api.Models.MobileLine", "MobileLine")
|
||||
.WithMany("Muregs")
|
||||
.HasForeignKey("MobileLineId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("MobileLine");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("line_gestao_api.Models.Notification", b =>
|
||||
{
|
||||
b.HasOne("line_gestao_api.Models.User", "User")
|
||||
b.HasOne("line_gestao_api.Models.ApplicationUser", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
|
@ -544,15 +774,55 @@ namespace line_gestao_api.Migrations
|
|||
b.Navigation("VigenciaLine");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("line_gestao_api.Models.MuregLine", b =>
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<Guid>", b =>
|
||||
{
|
||||
b.HasOne("line_gestao_api.Models.MobileLine", "MobileLine")
|
||||
.WithMany("Muregs")
|
||||
.HasForeignKey("MobileLineId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole<Guid>", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("RoleId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<Guid>", b =>
|
||||
{
|
||||
b.HasOne("line_gestao_api.Models.ApplicationUser", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<Guid>", b =>
|
||||
{
|
||||
b.HasOne("line_gestao_api.Models.ApplicationUser", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<Guid>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole<Guid>", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("RoleId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("MobileLine");
|
||||
b.HasOne("line_gestao_api.Models.ApplicationUser", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<Guid>", b =>
|
||||
{
|
||||
b.HasOne("line_gestao_api.Models.ApplicationUser", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("line_gestao_api.Models.MobileLine", b =>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,11 @@
|
|||
using Microsoft.AspNetCore.Identity;
|
||||
|
||||
namespace line_gestao_api.Models;
|
||||
|
||||
public class ApplicationUser : IdentityUser<Guid>, ITenantEntity
|
||||
{
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public Guid TenantId { get; set; }
|
||||
public bool IsActive { get; set; } = true;
|
||||
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
||||
}
|
||||
|
|
@ -1,8 +1,9 @@
|
|||
namespace line_gestao_api.Models
|
||||
{
|
||||
public class BillingClient
|
||||
public class BillingClient : ITenantEntity
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
public Guid TenantId { get; set; }
|
||||
public string Tipo { get; set; } = "PF"; // "PF" ou "PJ"
|
||||
|
||||
public int Item { get; set; }
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
namespace line_gestao_api.Models;
|
||||
|
||||
public interface ITenantEntity
|
||||
{
|
||||
Guid TenantId { get; set; }
|
||||
}
|
||||
|
|
@ -2,10 +2,12 @@
|
|||
|
||||
namespace line_gestao_api.Models
|
||||
{
|
||||
public class MobileLine
|
||||
public class MobileLine : ITenantEntity
|
||||
{
|
||||
public Guid Id { get; set; } = Guid.NewGuid();
|
||||
|
||||
public Guid TenantId { get; set; }
|
||||
|
||||
public int Item { get; set; }
|
||||
[MaxLength(80)]
|
||||
public string? Conta { get; set; }
|
||||
|
|
|
|||
|
|
@ -2,10 +2,12 @@
|
|||
|
||||
namespace line_gestao_api.Models
|
||||
{
|
||||
public class MuregLine
|
||||
public class MuregLine : ITenantEntity
|
||||
{
|
||||
public Guid Id { get; set; } = Guid.NewGuid();
|
||||
|
||||
public Guid TenantId { get; set; }
|
||||
|
||||
public int Item { get; set; }
|
||||
|
||||
// Linha escolhida da GERAL no momento do mureg
|
||||
|
|
|
|||
|
|
@ -2,10 +2,12 @@
|
|||
|
||||
namespace line_gestao_api.Models;
|
||||
|
||||
public class Notification
|
||||
public class Notification : ITenantEntity
|
||||
{
|
||||
public Guid Id { get; set; } = Guid.NewGuid();
|
||||
|
||||
public Guid TenantId { get; set; }
|
||||
|
||||
[Required]
|
||||
public string Tipo { get; set; } = string.Empty;
|
||||
|
||||
|
|
@ -29,7 +31,7 @@ public class Notification
|
|||
public string DedupKey { get; set; } = string.Empty;
|
||||
|
||||
public Guid? UserId { get; set; }
|
||||
public User? User { get; set; }
|
||||
public ApplicationUser? User { get; set; }
|
||||
|
||||
public Guid? VigenciaLineId { get; set; }
|
||||
public VigenciaLine? VigenciaLine { get; set; }
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
namespace line_gestao_api.Models;
|
||||
|
||||
public class Tenant
|
||||
{
|
||||
public Guid Id { get; set; } = Guid.NewGuid();
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
||||
}
|
||||
|
|
@ -2,10 +2,12 @@
|
|||
|
||||
namespace line_gestao_api.Models
|
||||
{
|
||||
public class TrocaNumeroLine
|
||||
public class TrocaNumeroLine : ITenantEntity
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
|
||||
public Guid TenantId { get; set; }
|
||||
|
||||
public int Item { get; set; }
|
||||
|
||||
public string? LinhaAntiga { get; set; }
|
||||
|
|
|
|||
|
|
@ -1,23 +0,0 @@
|
|||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace line_gestao_api.Models;
|
||||
|
||||
public class User
|
||||
{
|
||||
public Guid Id { get; set; } = Guid.NewGuid();
|
||||
|
||||
[Required, MaxLength(120)]
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
[Required, MaxLength(120)]
|
||||
public string Email { get; set; } = string.Empty;
|
||||
|
||||
[MaxLength(20)]
|
||||
public string Phone { get; set; } = string.Empty;
|
||||
|
||||
|
||||
[Required]
|
||||
public string PasswordHash { get; set; } = string.Empty;
|
||||
|
||||
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
||||
}
|
||||
|
|
@ -3,11 +3,13 @@ using System.ComponentModel.DataAnnotations.Schema;
|
|||
|
||||
namespace line_gestao_api.Models
|
||||
{
|
||||
public class UserData
|
||||
public class UserData : ITenantEntity
|
||||
{
|
||||
[Key]
|
||||
public Guid Id { get; set; }
|
||||
|
||||
public Guid TenantId { get; set; }
|
||||
|
||||
public int Item { get; set; }
|
||||
|
||||
public string? Linha { get; set; }
|
||||
|
|
|
|||
|
|
@ -2,10 +2,12 @@
|
|||
|
||||
namespace line_gestao_api.Models
|
||||
{
|
||||
public class VigenciaLine
|
||||
public class VigenciaLine : ITenantEntity
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
|
||||
public Guid TenantId { get; set; }
|
||||
|
||||
public int Item { get; set; }
|
||||
|
||||
public string? Conta { get; set; }
|
||||
|
|
|
|||
19
Program.cs
19
Program.cs
|
|
@ -1,8 +1,10 @@
|
|||
using System.Text;
|
||||
using line_gestao_api.Data;
|
||||
using line_gestao_api.Models;
|
||||
using line_gestao_api.Services;
|
||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||
using Microsoft.AspNetCore.Http.Features;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
|
||||
|
|
@ -31,6 +33,18 @@ builder.Services.AddDbContext<AppDbContext>(options =>
|
|||
options.UseNpgsql(builder.Configuration.GetConnectionString("Default"))
|
||||
);
|
||||
|
||||
builder.Services.AddHttpContextAccessor();
|
||||
builder.Services.AddScoped<ITenantProvider, TenantProvider>();
|
||||
|
||||
builder.Services.AddIdentityCore<ApplicationUser>(options =>
|
||||
{
|
||||
options.Password.RequiredLength = 6;
|
||||
options.User.RequireUniqueEmail = false;
|
||||
})
|
||||
.AddRoles<IdentityRole<Guid>>()
|
||||
.AddEntityFrameworkStores<AppDbContext>()
|
||||
.AddDefaultTokenProviders();
|
||||
|
||||
// ✅ Swagger
|
||||
builder.Services.AddEndpointsApiExplorer();
|
||||
builder.Services.AddSwaggerGen();
|
||||
|
|
@ -61,6 +75,8 @@ builder.Services.AddAuthorization();
|
|||
builder.Services.Configure<NotificationOptions>(builder.Configuration.GetSection("Notifications"));
|
||||
builder.Services.AddHostedService<VigenciaNotificationBackgroundService>();
|
||||
|
||||
builder.Services.Configure<SeedOptions>(builder.Configuration.GetSection("Seed"));
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
if (app.Environment.IsDevelopment())
|
||||
|
|
@ -75,8 +91,11 @@ app.UseHttpsRedirection();
|
|||
app.UseCors("Front");
|
||||
|
||||
app.UseAuthentication();
|
||||
app.UseMiddleware<TenantMiddleware>();
|
||||
app.UseAuthorization();
|
||||
|
||||
app.MapControllers();
|
||||
|
||||
await SeedData.EnsureSeedDataAsync(app.Services);
|
||||
|
||||
app.Run();
|
||||
|
|
|
|||
|
|
@ -0,0 +1,7 @@
|
|||
namespace line_gestao_api.Services;
|
||||
|
||||
public interface ITenantProvider
|
||||
{
|
||||
Guid? TenantId { get; }
|
||||
void SetTenantId(Guid? tenantId);
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
using System.Security.Claims;
|
||||
|
||||
namespace line_gestao_api.Services;
|
||||
|
||||
public class TenantMiddleware
|
||||
{
|
||||
private readonly RequestDelegate _next;
|
||||
|
||||
public TenantMiddleware(RequestDelegate next)
|
||||
{
|
||||
_next = next;
|
||||
}
|
||||
|
||||
public async Task InvokeAsync(HttpContext context, ITenantProvider tenantProvider)
|
||||
{
|
||||
Guid? tenantId = null;
|
||||
var claim = context.User.FindFirst("tenantId")?.Value
|
||||
?? context.User.FindFirst("tenant")?.Value;
|
||||
|
||||
if (Guid.TryParse(claim, out var parsed))
|
||||
{
|
||||
tenantId = parsed;
|
||||
}
|
||||
|
||||
tenantProvider.SetTenantId(tenantId);
|
||||
|
||||
try
|
||||
{
|
||||
await _next(context);
|
||||
}
|
||||
finally
|
||||
{
|
||||
tenantProvider.SetTenantId(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
using System.Security.Claims;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace line_gestao_api.Services;
|
||||
|
||||
public class TenantProvider : ITenantProvider
|
||||
{
|
||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||
private static readonly AsyncLocal<Guid?> CurrentTenant = new();
|
||||
|
||||
public TenantProvider(IHttpContextAccessor httpContextAccessor)
|
||||
{
|
||||
_httpContextAccessor = httpContextAccessor;
|
||||
}
|
||||
|
||||
public Guid? TenantId => CurrentTenant.Value ?? ResolveFromClaims();
|
||||
|
||||
public void SetTenantId(Guid? tenantId)
|
||||
{
|
||||
CurrentTenant.Value = tenantId;
|
||||
}
|
||||
|
||||
private Guid? ResolveFromClaims()
|
||||
{
|
||||
var claim = _httpContextAccessor.HttpContext?.User?.FindFirst("tenantId")?.Value
|
||||
?? _httpContextAccessor.HttpContext?.User?.FindFirst("tenant")?.Value;
|
||||
|
||||
return Guid.TryParse(claim, out var tenantId) ? tenantId : null;
|
||||
}
|
||||
}
|
||||
|
|
@ -41,6 +41,7 @@ public class VigenciaNotificationBackgroundService : BackgroundService
|
|||
{
|
||||
using var scope = _scopeFactory.CreateScope();
|
||||
var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
var tenantProvider = scope.ServiceProvider.GetRequiredService<ITenantProvider>();
|
||||
|
||||
if (!await TableExistsAsync(db, "Notifications", stoppingToken))
|
||||
{
|
||||
|
|
@ -48,6 +49,53 @@ public class VigenciaNotificationBackgroundService : BackgroundService
|
|||
return;
|
||||
}
|
||||
|
||||
var tenants = await db.Tenants.AsNoTracking().ToListAsync(stoppingToken);
|
||||
if (tenants.Count == 0)
|
||||
{
|
||||
_logger.LogWarning("Nenhum tenant encontrado para gerar notificações.");
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var tenant in tenants)
|
||||
{
|
||||
tenantProvider.SetTenantId(tenant.Id);
|
||||
await ProcessTenantAsync(db, tenant.Id, stoppingToken);
|
||||
}
|
||||
|
||||
tenantProvider.SetTenantId(null);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Erro ao gerar notificações de vigência.");
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task<bool> TableExistsAsync(AppDbContext db, string tableName, CancellationToken stoppingToken)
|
||||
{
|
||||
if (!db.Database.IsRelational())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
var connection = db.Database.GetDbConnection();
|
||||
if (connection.State != System.Data.ConnectionState.Open)
|
||||
{
|
||||
await connection.OpenAsync(stoppingToken);
|
||||
}
|
||||
|
||||
await using var command = connection.CreateCommand();
|
||||
command.CommandText = "SELECT EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = @tableName)";
|
||||
var parameter = command.CreateParameter();
|
||||
parameter.ParameterName = "tableName";
|
||||
parameter.Value = tableName;
|
||||
command.Parameters.Add(parameter);
|
||||
|
||||
var result = await command.ExecuteScalarAsync(stoppingToken);
|
||||
return result is bool exists && exists;
|
||||
}
|
||||
|
||||
private async Task ProcessTenantAsync(AppDbContext db, Guid tenantId, CancellationToken stoppingToken)
|
||||
{
|
||||
var today = DateTime.UtcNow.Date;
|
||||
var reminderDays = _options.ReminderDays
|
||||
.Distinct()
|
||||
|
|
@ -110,7 +158,8 @@ public class VigenciaNotificationBackgroundService : BackgroundService
|
|||
usuario: usuario,
|
||||
cliente: cliente,
|
||||
linha: linha,
|
||||
vigenciaLineId: vigencia.Id);
|
||||
vigenciaLineId: vigencia.Id,
|
||||
tenantId: tenantId);
|
||||
|
||||
candidates.Add(notification);
|
||||
continue;
|
||||
|
|
@ -129,7 +178,8 @@ public class VigenciaNotificationBackgroundService : BackgroundService
|
|||
usuario: usuario,
|
||||
cliente: cliente,
|
||||
linha: linha,
|
||||
vigenciaLineId: vigencia.Id);
|
||||
vigenciaLineId: vigencia.Id,
|
||||
tenantId: tenantId);
|
||||
|
||||
candidates.Add(notification);
|
||||
}
|
||||
|
|
@ -159,35 +209,6 @@ public class VigenciaNotificationBackgroundService : BackgroundService
|
|||
await db.Notifications.AddRangeAsync(toInsert, stoppingToken);
|
||||
await db.SaveChangesAsync(stoppingToken);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Erro ao gerar notificações de vigência.");
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task<bool> TableExistsAsync(AppDbContext db, string tableName, CancellationToken stoppingToken)
|
||||
{
|
||||
if (!db.Database.IsRelational())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
var connection = db.Database.GetDbConnection();
|
||||
if (connection.State != System.Data.ConnectionState.Open)
|
||||
{
|
||||
await connection.OpenAsync(stoppingToken);
|
||||
}
|
||||
|
||||
await using var command = connection.CreateCommand();
|
||||
command.CommandText = "SELECT EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = @tableName)";
|
||||
var parameter = command.CreateParameter();
|
||||
parameter.ParameterName = "tableName";
|
||||
parameter.Value = tableName;
|
||||
command.Parameters.Add(parameter);
|
||||
|
||||
var result = await command.ExecuteScalarAsync(stoppingToken);
|
||||
return result is bool exists && exists;
|
||||
}
|
||||
|
||||
private static Notification BuildNotification(
|
||||
string tipo,
|
||||
|
|
@ -199,7 +220,8 @@ public class VigenciaNotificationBackgroundService : BackgroundService
|
|||
string? usuario,
|
||||
string? cliente,
|
||||
string? linha,
|
||||
Guid vigenciaLineId)
|
||||
Guid vigenciaLineId,
|
||||
Guid tenantId)
|
||||
{
|
||||
return new Notification
|
||||
{
|
||||
|
|
@ -215,7 +237,8 @@ public class VigenciaNotificationBackgroundService : BackgroundService
|
|||
Usuario = usuario,
|
||||
Cliente = cliente,
|
||||
Linha = linha,
|
||||
VigenciaLineId = vigenciaLineId
|
||||
VigenciaLineId = vigenciaLineId,
|
||||
TenantId = tenantId
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,5 +8,11 @@
|
|||
"Notifications": {
|
||||
"CheckIntervalMinutes": 60,
|
||||
"ReminderDays": [30, 15, 7]
|
||||
},
|
||||
"Seed": {
|
||||
"DefaultTenantName": "Default",
|
||||
"AdminName": "Administrador",
|
||||
"AdminEmail": "admin@linegestao.local",
|
||||
"AdminPassword": "Admin123!"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,5 +11,11 @@
|
|||
"Notifications": {
|
||||
"CheckIntervalMinutes": 60,
|
||||
"ReminderDays": [30, 15, 7]
|
||||
},
|
||||
"Seed": {
|
||||
"DefaultTenantName": "Default",
|
||||
"AdminName": "Administrador",
|
||||
"AdminEmail": "admin@linegestao.local",
|
||||
"AdminPassword": "Admin123!"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
<ItemGroup>
|
||||
<PackageReference Include="ClosedXML" Version="0.105.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="10.0.1" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="10.0.1" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="10.0.1" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="10.0.1" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="10.0.1">
|
||||
|
|
|
|||
Loading…
Reference in New Issue