Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
258a1ed
adicionado arquivos .gitignore
GabrielCarvalho0812 Jan 29, 2026
73bb86f
inicial commit
GabrielCarvalho0812 Jan 29, 2026
bf48f23
configuração inicial do projeto
GabrielCarvalho0812 Jan 29, 2026
2a09ebb
feat: cria entidade Livro no domínio
GabrielCarvalho0812 Jan 29, 2026
cae0f9c
feat: adiciona DTOs de criação e leitura de livro
GabrielCarvalho0812 Jan 29, 2026
2180c01
feat: configuração DbContext Entity Frameork Core
GabrielCarvalho0812 Jan 29, 2026
619285f
chore: adiciona migration inicial do banco de dados
GabrielCarvalho0812 Jan 29, 2026
a0d5b3a
feat: implementa repositório de livros
GabrielCarvalho0812 Jan 29, 2026
245573b
feat: adiciona Service de Livros
GabrielCarvalho0812 Jan 29, 2026
392fd52
feat: adiciona Controllers de livros
GabrielCarvalho0812 Jan 29, 2026
0b5f5b9
feat: implementando melhorias de retorno HTTP
GabrielCarvalho0812 Jan 30, 2026
0421eae
feat: implementando authentication
GabrielCarvalho0812 Jan 30, 2026
2c8fd90
feat: melhorias metodo Delete e Update
GabrielCarvalho0812 Jan 30, 2026
c580f07
feat: adicona losg na camada de service
GabrielCarvalho0812 Jan 30, 2026
532d31f
refactor: reorganiza metodo getLivroById e UpdateLivro
GabrielCarvalho0812 Jan 30, 2026
df9d354
refactor: criaUpdate Dto para organizar dados do PUT
GabrielCarvalho0812 Jan 30, 2026
e790d96
chore: adiciona pasta logs/ ao .gitignore
GabrielCarvalho0812 Jan 30, 2026
656fe6e
feat: implementa paginação e filtro por nome no GET /livro
GabrielCarvalho0812 Jan 30, 2026
02f13a1
feat: adicona configuraçoes para documentação Swagger
GabrielCarvalho0812 Jan 30, 2026
ac5b96d
feat: documentação de endpoints para exibição no Swagger
GabrielCarvalho0812 Jan 30, 2026
cf1ec01
alreando appsettings.Development.json
GabrielCarvalho0812 Jan 30, 2026
c1e6d76
feat: criando arquivo appsettings.Development.json
GabrielCarvalho0812 Jan 30, 2026
8c950e0
refactor: alterando configuraçoes de senha
GabrielCarvalho0812 Jan 30, 2026
e2b03d6
feat : adiciona Database seed data para criaçaõ inicial de livros
GabrielCarvalho0812 Jan 30, 2026
a30896c
docs: finaliza README do desafio back-end Dorotech
GabrielCarvalho0812 Feb 2, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Build e pastas temporárias
bin/
obj/
out/

# Configurações da IDE Rider
.idea/
*.sln.iml

# Configurações do Visual Studio Code
.vscode/

# Arquivos de log e temporários
/Logs
*.log
*.tmp
*.temp

# Configurações do sistema
.DS_Store
Thumbs.db

# Arquivos de backup do Visual Studio
*.user
*.suo

# Arquivos de pacotes NuGet
*.nupkg
*.snupkg
packages/

# Publicação e publicação local
publish/

# Configurações locais (NÃO subir)
appsettings.Development.json
12 changes: 12 additions & 0 deletions Business/Entities/Livro.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
namespace dorotech_csharp_test.Business;

public class Livro
{
public Guid Id { get; set; } = Guid.NewGuid();
public string Nome { get; set; }
public string? Descricao { get; set; }
public decimal Preco { get; set; }
public int Estoque { get; set; }
public DateTime DataCadastro { get; set; } = DateTime.UtcNow;

}
11 changes: 11 additions & 0 deletions Business/Interfaces/Repositories/ILivroRepository.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
namespace dorotech_csharp_test.Business.Interfaces.Repositories;

public interface ILivroRepository
{
Task<List<Livro>> ObeterTodosLivros();
Task<bool> ExisteLivroComNome(string livroNome);
Task Adicionar(Livro livro);
Task<Livro?> ObterLivroPeloId(Guid id);
Task<bool> Delete(Guid id);
Task<Livro> Update(Guid id, Livro livroAtualizado);
}
76 changes: 76 additions & 0 deletions Business/Services/LivroService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
using dorotech_csharp_test.Business.Interfaces.Repositories;

namespace dorotech_csharp_test.Business.Services;

public class LivroService
{
private readonly ILivroRepository _livroRepository;
private readonly ILogger<LivroService> _logger;

public LivroService(ILivroRepository livroRepository, ILogger<LivroService> logger)
{
_livroRepository = livroRepository;
_logger = logger;
}

public async Task CreateLivro(Livro livro)
{
_logger.LogInformation("Inicio do Cadastro : {Nome}", livro.Nome);
if (await _livroRepository.ExisteLivroComNome(livro.Nome))
{
_logger.LogWarning("Livro já cadastrado: {Nome}", livro.Nome);
throw new InvalidOperationException("Livro já Cadastrado");
}

await _livroRepository.Adicionar(livro);
_logger.LogInformation(
"Livro cadastrado com sucesso. Id: {Id}", livro.Id);
}


public async Task<IEnumerable<Livro>> ObterTodoslivros( int page, int pageSize, string? nome)
{
_logger.LogInformation("Consulta de todos os livros");
return (await _livroRepository.ObeterTodosLivros())
.OrderBy(l => l.Nome)
.Skip((page - 1) * pageSize)
.Take(pageSize);
}


public async Task<Livro?> ObterLivroPeloId(Guid id)
{
_logger.LogInformation("Consulta de Livro {Id}", id);
return await _livroRepository.ObterLivroPeloId(id);
}


public async Task Delete(Guid id)
{
_logger.LogInformation("Tentando excluir livro {Id}", id);
var deleted = await _livroRepository.Delete(id);
if (!deleted)
{
_logger.LogWarning(
"Falha ao excluir. Livro não encontrado {Id}", id);
throw new KeyNotFoundException("livro nao encontrado");
}
_logger.LogInformation(
"Livro excluído com sucesso {Id}", id);
}

public async Task<Livro> Upadate(Guid id, Livro livroAtualizado)
{
_logger.LogInformation("Tentando atualizar livro {Id}", id);
var livro = await _livroRepository.Update(id, livroAtualizado);
if (livro == null)
{
_logger.LogWarning(
"Livro não encontrado para atualização {Id}", id);
throw new KeyNotFoundException("Livro Não encontrado");
}
_logger.LogInformation(
"Livro atualizado com sucesso {Id}", id);
return livro;
}
}
31 changes: 31 additions & 0 deletions Business/Services/TokenService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using Microsoft.IdentityModel.Tokens;

namespace dorotech_csharp_test.Business.Services;

public class TokenService
{
public string GenerateToken(string role)
{
var claims = new[]
{
new Claim(ClaimTypes.Role, role)
};

var key = new SymmetricSecurityKey(
Encoding.UTF8.GetBytes("minha-chave-super-secreta-com-32-caracteres")
);

var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);

var token = new JwtSecurityToken(
claims: claims,
expires: DateTime.Now.AddHours(2),
signingCredentials: creds
);

return new JwtSecurityTokenHandler().WriteToken(token);
}
}
12 changes: 12 additions & 0 deletions Data/Context/DorotechContext.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using dorotech_csharp_test.Business;
using Microsoft.EntityFrameworkCore;

namespace dorotech_csharp_test.Data.Context;

public class DorotechContext : DbContext
{
public DorotechContext(DbContextOptions<DorotechContext> options) : base(options)
{
}
public DbSet<Livro> Livros { get; set; }
}
67 changes: 67 additions & 0 deletions Data/Repositories/LivroRepository.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
using dorotech_csharp_test.Business;
using dorotech_csharp_test.Business.Interfaces.Repositories;
using dorotech_csharp_test.Data.Context;
using Microsoft.EntityFrameworkCore;

namespace dorotech_csharp_test.Data.Repositories;

public class LivroRepository : ILivroRepository
{
private readonly DorotechContext _context;

public LivroRepository(DorotechContext context)
{
_context = context;
}

public async Task<List<Livro>> ObeterTodosLivros()
{
return await _context.Livros
.OrderBy(l => l.Nome)
.ToListAsync();
}

public Task<bool> ExisteLivroComNome(string livroNome)
{
return _context.Livros.AnyAsync(l => l.Nome == livroNome);
}

public async Task Adicionar(Livro livro)
{
await _context.Livros.AddAsync(livro);
await _context.SaveChangesAsync();
}

public async Task<Livro?> ObterLivroPeloId(Guid id)
{
return await _context.Livros.FindAsync(id);
}

public async Task<bool> Delete(Guid id)
{
var livro = await _context.Livros.FindAsync(id);
if (livro == null)
return false;

_context.Livros.Remove(livro); //remove o livro
await _context.SaveChangesAsync(); //Salva no Banco
return true;
}

public async Task<Livro?> Update(Guid id, Livro livroAtualizado)
{
var livro = await _context.Livros.FindAsync(id);
if (livro == null)
return null;

livro.Nome = livroAtualizado.Nome;
livro.Descricao = livroAtualizado.Descricao;
livro.Estoque = livroAtualizado.Estoque;
livro.Preco = livroAtualizado.Preco;

_context.Livros.Update(livro);
await _context.SaveChangesAsync();

return livro;
}
}
40 changes: 40 additions & 0 deletions Data/Seed/SeedData.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using dorotech_csharp_test.Business;
using dorotech_csharp_test.Data.Context;

namespace dorotech_csharp_test.Data.Seed;

public static class SeedData
{
public static void Initialize(DorotechContext context)
{
// Checa se já existem livros no banco
if (!context.Livros.Any())
{
context.Livros.AddRange(
new Livro
{
Nome = "Garen",
Descricao = "Livro teste",
Preco = 50,
Estoque = 10
},
new Livro
{
Nome = "C#",
Descricao = "Livro de programação",
Preco = 80,
Estoque = 5
},
new Livro
{
Nome = "Matematica",
Descricao = "Livro de Matematica",
Preco = 70,
Estoque = 7
}
);

context.SaveChanges(); // Salva no banco
}
}
}
29 changes: 29 additions & 0 deletions DorotechApi/Auth/AuthController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using dorotech_csharp_test.Business.Services;
using Microsoft.AspNetCore.Mvc;

namespace dorotech_csharp_test.DorotechApi.Auth;

[ApiController]
[Route("api/auth")]
public class AuthController : ControllerBase
{
private readonly TokenService _tokenService;

public AuthController(TokenService tokenService)
{
_tokenService = tokenService;
}

[HttpPost("login")]
public IActionResult Login(LoginDto dto)
{

if (dto.Usuario == "admin" && dto.Senha == "123")
{
var token = _tokenService.GenerateToken("Admin");
return Ok(new { token });
}

return Unauthorized();
}
}
7 changes: 7 additions & 0 deletions DorotechApi/Auth/LoginDto.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace dorotech_csharp_test.DorotechApi.Auth;

public class LoginDto
{
public string Usuario { get; set; }
public string Senha { get; set; }
}
Loading