Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
06d6740
chore: adicionando git ignore
JoseVitorLemos Sep 28, 2025
89d2870
chore: Adicionando CRUD completo + Autenticação e loggs de Erros via …
JoseVitorLemos Sep 28, 2025
2e72057
chore: adicionando e configurando Lib AuditLog para logs personalizad…
JoseVitorLemos Sep 28, 2025
1e6b5fa
chore: adicionando configuração para ignorar campo sensível no log
JoseVitorLemos Sep 28, 2025
a5e5618
chore: adicionando scripts DDL
JoseVitorLemos Sep 28, 2025
287e752
chore: configuração do swagger e adição e ajustes de summario dos end…
JoseVitorLemos Sep 28, 2025
5c4e217
fix: atualização tabelas DDL auditLogs e Login
JoseVitorLemos Sep 28, 2025
d529883
refactor: removendo pacotes e linhas não ultilizados
JoseVitorLemos Sep 28, 2025
30f8687
refactor: adição de cancelatioToken para monitoramento da requisição …
JoseVitorLemos Sep 29, 2025
ce7129f
test: adição de testes unitários em todos os recursos da aplicação
JoseVitorLemos Sep 29, 2025
57ff204
refactor: renomeando pasta Shared
JoseVitorLemos Sep 29, 2025
88f0cae
chore: adição do curriculo
JoseVitorLemos Sep 29, 2025
6a0aa4c
test: ajuste Audit para testes unitários não tentar comunicar com ins…
JoseVitorLemos Sep 29, 2025
7867dc4
chore: adição de collections postman
JoseVitorLemos Sep 29, 2025
a18ab63
fix: movendo testes integrados para projeto novo criado e corrigindo …
JoseVitorLemos Sep 30, 2025
6b11581
fix: ajuste para provider em teste integrado não tentar integrar com …
JoseVitorLemos Sep 30, 2025
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
484 changes: 484 additions & 0 deletions .gitignore

Large diffs are not rendered by default.

Binary file added José Vitor Lemos Oliveira Currículo.pdf
Binary file not shown.
55 changes: 55 additions & 0 deletions app/Api/Library.Api/Controllers/AuthenticateController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
using MediatR;
using Library.Shared.Responses;
using Microsoft.AspNetCore.Mvc;
using Library.Application.MediatR.Authenticate.Commands.SignIn;
using Library.Application.MediatR.Authenticate.Commands.SignUp;
using SignInResult = Library.Application.MediatR.Authenticate.Commands.SignIn.SignInResult;

namespace Library.Api.Controllers;

[ApiController]
[Route("[controller]")]
public class AuthenticateController(IMediator mediator) : ControllerBase
{
private readonly IMediator _mediator = mediator;

/// <summary>
/// Realiza o login no sistema, para acessar os endpoints com n�vel de acesso administrador.
/// </summary>
/// <see cref="SignInCommand.UserName"/>
/// Par�metros para autenticar o usu�rio por nome uo email cadastrado
/// <see cref="SignInCommand.Password"/>
/// Senha do usu�rio cadastrado
/// <returns>
/// Retorna um <see cref="OkObjectResult"/> contendo um objeto do tipo
/// <see cref="SignInResult"/> Ir� retornar o token caso o userName/Login
/// e password sejam v�lidos.
/// </returns>
[HttpPost("SignIn")]
[ProducesResponseType(typeof(SignInResult), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ExceptionResponse), StatusCodes.Status400BadRequest)]
[ProducesResponseType(typeof(ExceptionResponse), StatusCodes.Status401Unauthorized)]
public async Task<IActionResult> SignIn([FromBody] SignInCommand query)
=> Ok(await _mediator.Send(query));

/// <summary>
/// Realiza o cadastro para o usu�rio Administrador do sistema
/// </summary>
/// <see cref="SignUpCommand.UserName"/>
/// Par�metros que representa o Nome do usu�rio no sistema.
/// <see cref="SignUpCommand.Email"/>
/// Par�metros que representa o Email do usu�rio no sistema
/// <see cref="SignUpCommand.Password"/>
/// Senha do usu�rio que ser� cadastrado.
/// <returns>
/// Retorna um <see cref="OkObjectResult"/> contendo um objeto do tipo
/// <see cref="SignUpResult"/> Ir� retornar o token caso registre
/// o usu�rio com sucesso.
/// </returns>
[HttpPost("SignUp")]
[ProducesResponseType(typeof(SignUpResult), StatusCodes.Status201Created)]
[ProducesResponseType(typeof(ExceptionResponse), StatusCodes.Status400BadRequest)]
[ProducesResponseType(typeof(ExceptionResponse), StatusCodes.Status401Unauthorized)]
public async Task<IActionResult> SignUp([FromBody] SignUpCommand command)
=> CreatedAtAction(nameof(SignUp), await _mediator.Send(command));
}
114 changes: 114 additions & 0 deletions app/Api/Library.Api/Controllers/BookController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
using Library.Application.Common.Paged;
using Library.Application.MediatR.Books.Commands.Create;
using Library.Application.MediatR.Books.Commands.Delete;
using Library.Application.MediatR.Books.Commands.Update;
using Library.Application.MediatR.Books.Queries.GetAll;
using Library.Shared.Responses;
using MediatR;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Swashbuckle.AspNetCore.Annotations;

namespace Library.Api.Controllers;

[ApiController]
[Route("[controller]")]
public class BookController(IMediator mediator) : ControllerBase
{
private readonly IMediator _mediator = mediator;

/// <summary>
/// Lista todos os livros cadastrados na Library.
/// </summary>
/// <param name="query">
/// Par�metros de consulta para pagina��o e filtro:
/// <list type="bullet">
/// <item><description><c>Page</c> � n�mero da p�gina (padr�o: 1).</description></item>
/// <item><description><c>PageSize</c> � quantidade de registros por p�gina (padr�o: 50).</description></item>
/// <item><description><c>OrderBy</c> � ordena��o dos resultados ("asc" ou "desc").</description></item>
/// <item><description><c>Name</c> � filtro opcional pelo nome do livro.</description></item>
/// </list>
/// </param>
/// <returns>
/// Retorna um <see cref="OkObjectResult"/> contendo um objeto do tipo
/// <see cref="PagedResult{BooksGetAllResult}"/> com os dados paginados dos livros,
/// incluindo informa��es de total de registros e n�mero de p�ginas.
/// </returns>
[HttpGet]
[AllowAnonymous]
[ProducesResponseType(typeof(PagedResult<BooksGetAllResult>), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ExceptionResponse), StatusCodes.Status400BadRequest)]
public async Task<IActionResult> GetAll([FromQuery] BooksGetAllQuery query)
=> Ok(await _mediator.Send(query));

/// <summary>
/// Cadastrar um novo livro na Library.
/// </summary>
/// <param name="command">
/// Objeto contendo os dados necess�rios para criar o livro,
/// incluindo <see cref="BookCreateCommand.Name"/>,
/// <see cref="BookCreateCommand.Author"/> e
/// <see cref="BookCreateCommand.Summary"/>.
/// </param>
/// <returns>
/// Retorna um <see cref="CreatedAtActionResult"/>.
/// O objeto retornado cont�m o identificador �nico do livro.
/// </returns>
[HttpPost]
[Authorize("Administrator")]
[ProducesResponseType(typeof(BookCreateResult), StatusCodes.Status201Created)]
[ProducesResponseType(typeof(ExceptionResponse), StatusCodes.Status400BadRequest)]
[ProducesResponseType(typeof(ExceptionResponse), StatusCodes.Status401Unauthorized)]
public async Task<IActionResult> Create([FromBody] BookCreateCommand command)
{
var result = await _mediator.Send(command);
return CreatedAtAction(nameof(Create), new { id = result.Id }, result);
}

/// <summary>
/// Edita um livro existente
/// </summary>
/// <param name="command">
/// Objeto contendo os dados necess�rios para atualziar um livro,
/// incluindo <see cref="BookUpdateCommand.Id"/>,
/// <see cref="BookUpdateCommand.Name"/> e
/// <see cref="BookUpdateCommand.Author"/>.
/// <see cref="BookUpdateCommand.Summary"/>.
/// </param>
/// <returns>
/// Retorna um <see cref="NoContentResult"/>.
/// N�o possui um objeto retornado quando obtem successo.
/// </returns>
[HttpPut]
[Authorize("Administrator")]
[ProducesResponseType(typeof(Unit), StatusCodes.Status204NoContent)]
[ProducesResponseType(typeof(ExceptionResponse), StatusCodes.Status400BadRequest)]
[ProducesResponseType(typeof(ExceptionResponse), StatusCodes.Status401Unauthorized)]
public async Task<IActionResult> Update([FromBody] BookUpdateCommand command)
{
var result = await _mediator.Send(command);
return NoContent();
}

/// <summary>
/// Exclui um livro existente
/// </summary>
/// <param name="id">
/// Objeto contendo os dados necess�rios para remover um livro,
/// <see cref="BookUpdateCommand.Id"/>
/// </param>
/// <returns>
/// Retorna um <see cref="NoContentResult"/>.
/// N�o possui um objeto retornado quando obtem successo.
/// </returns>
[HttpDelete("{id}")]
[Authorize("Administrator")]
[ProducesResponseType(typeof(Unit), StatusCodes.Status204NoContent)]
[ProducesResponseType(typeof(ExceptionResponse), StatusCodes.Status400BadRequest)]
[ProducesResponseType(typeof(ExceptionResponse), StatusCodes.Status401Unauthorized)]
public async Task<IActionResult> Delete([FromRoute] string id)
{
await _mediator.Send(new BookDeleteCommand(id));
return NoContent();
}
}
16 changes: 16 additions & 0 deletions app/Api/Library.Api/Library.Api.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<NoWarn>$(NoWarn);1591</NoWarn>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\Library.Application\Library.Application.csproj" />
<ProjectReference Include="..\Library.IoC\Library.IoC.csproj" />
</ItemGroup>

</Project>
45 changes: 45 additions & 0 deletions app/Api/Library.Api/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
using Serilog;
using Library.IoC.Shared;
using Library.IoC.Api.Swagger;
using Library.IoC.Application;
using Library.IoC.CrossCutting;
using Library.IoC.Infraestructure;
using Library.Shared.Middlewares;

internal class Program
{
private static void Main(string[] args)
{
var builder = WebApplication.CreateBuilder(args);

IServiceCollection services = builder.Services;

services.AddApiServices();
services.AddApplication();
services.AddCrossCutting();
services.AddInfraestruucture();
services.AddShared();

builder.Host.UseSerilog();

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}

app.UseHttpsRedirection();

app.UseMiddleware<GlobalExceptionHandling>();

app.UseAuthorization();

app.MapControllers();

app.UseCors("AllowAllOrigins");

app.Run();
}
}
41 changes: 41 additions & 0 deletions app/Api/Library.Api/Properties/launchSettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
{
"$schema": "http://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:19909",
"sslPort": 44335
}
},
"profiles": {
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "swagger",
"applicationUrl": "http://localhost:5055",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"https": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "swagger",
"applicationUrl": "https://localhost:7172;http://localhost:5055",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"launchUrl": "swagger",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
16 changes: 16 additions & 0 deletions app/Api/Library.Api/appsettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"ConnectionStrings": {
"DefaultConnection": "Server=127.0.0.1,1433;Database=LibraryDatabase;User ID=sa;Password=1q2w3e4r@#$;TrustServerCertificate=True;"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"JwtSettings": {
"expireHours": 2,
"secret": "073cd362bcefb4a1dd0ea1320591bde21s231xsd1u23h12u3h21"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using MediatR;
using FluentValidation;

namespace Library.Application.Common.Behaviours;

public class ValidationBehaviour<TRequest, TResponse>(IEnumerable<IValidator<TRequest>> validators) : IPipelineBehavior<TRequest, TResponse>
where TRequest : IRequest<TResponse>
{
private readonly IEnumerable<IValidator<TRequest>> _validators = validators;

public async Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next, CancellationToken cancellation)
{
if (_validators.Any())
{
var context = new ValidationContext<TRequest>(request);

var validationResults = await Task.WhenAll(
_validators.Select(v =>
v.ValidateAsync(context, cancellation)));

var failures = validationResults
.Where(r => r.Errors.Any())
.SelectMany(r => r.Errors)
.ToList();

if (failures.Any())
{
var errorMessages = failures.Select(f => f.ErrorMessage).ToList();
throw new ValidationException(failures);
}
}
return await next(cancellation);
}
}
8 changes: 8 additions & 0 deletions app/Api/Library.Application/Common/Paged/GetPaged.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace Library.Application.Common.Paged;

public class GetPaged
{
public int? Page { get; set; } = 1;
public int? PageSaze { get; set; } = 50;
public string OrderBy { get; set; } = "desc";
}
20 changes: 20 additions & 0 deletions app/Api/Library.Application/Common/Paged/PagedResult.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
namespace Library.Application.Common.Paged;

public class PagedResult<T>
{
public IEnumerable<T> Items { get; set; } = Enumerable.Empty<T>();
public int Page { get; set; }
public int PageSize { get; set; }
public int TotalCount { get; set; }
public int TotalPages => (int)Math.Ceiling((double)TotalCount / PageSize);

public PagedResult() { }

public PagedResult(IEnumerable<T> items, int totalCount, int page, int pageSize)
{
Items = items;
TotalCount = totalCount;
Page = page;
PageSize = pageSize;
}
}
20 changes: 20 additions & 0 deletions app/Api/Library.Application/Library.Application.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="FluentValidation" Version="12.0.0" />
<PackageReference Include="MediatR" Version="13.0.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Library.CrossCutting\Library.CrossCutting.csproj" />
<ProjectReference Include="..\Library.Domain\Library.Domain.csproj" />
<ProjectReference Include="..\Library.Shared\Library.Shared.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using MediatR;

namespace Library.Application.MediatR.Authenticate.Commands.SignIn;

public record SignInCommand : IRequest<SignInResult>
{
public string UserName { get; set; } = default!;
public string Password { get; set; } = default!;
}
Loading