Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Desafio Dorotech #4

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.vs
bin
obj
Binary file added CV - Guilherme Reis Araújo.pdf
Binary file not shown.
30 changes: 30 additions & 0 deletions LibraryAPI/API/API.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

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

<ItemGroup>
<Content Include="Properties\launchSettings.json" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="AutoMapper" Version="12.0.0" />
<PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="12.0.0" />
<PackageReference Include="BCrypt.Net-Core" Version="1.6.0" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="6.0.11" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="7.0.0">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="7.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="7.0.0" />
<PackageReference Include="Microsoft.IdentityModel.Tokens" Version="6.25.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.3" />
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="6.25.0" />
</ItemGroup>

</Project>
81 changes: 81 additions & 0 deletions LibraryAPI/API/Controllers/BooksController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
using AutoMapper;
using LibraryApi.Domain.Entities;
using LibraryApi.Domain.Services;
using LibraryApi.Extensions;
using LibraryApi.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

namespace LibraryApi.Controllers
{
[Route("/api/[controller]")]
public class BooksController : Controller
{
private readonly IBooksService _booksService;
private readonly IMapper _mapper;

public BooksController(IBooksService booksService, IMapper mapper)
{
_booksService = booksService;
_mapper = mapper;
}


[HttpGet]
[Authorize]
public async Task<IEnumerable<BookModel>> GetAllAsync([FromQuery] ListBooksModel model)
{
var books = await _booksService.ListAsync(model);
var models = _mapper.Map<IEnumerable<Book>, IEnumerable<BookModel>>(books);

return models;
}

[HttpPost]
[Authorize(Roles = "ADMINISTRADOR")]
public async Task<IActionResult> PostAsync([FromBody] SaveBookModel model)
{
if (!ModelState.IsValid)
return BadRequest(ModelState.GetErrorMessages());

var book = _mapper.Map<SaveBookModel, Book>(model);
var result = await _booksService.SaveAsync(book);

if (!result.Success)
return BadRequest(result.Message);

var BookModel = _mapper.Map<Book, BookModel>(result.Book);
return Ok(BookModel);
}

[HttpPut("{id}")]
[Authorize(Roles = "ADMINISTRADOR")]
public async Task<IActionResult> PutAsync(int id, [FromBody] SaveBookModel model)
{
if (!ModelState.IsValid)
return BadRequest(ModelState.GetErrorMessages());

var book = _mapper.Map<SaveBookModel, Book>(model);
var result = await _booksService.UpdateAsync(id, book);

if (!result.Success)
return BadRequest(result.Message);

var BookModel = _mapper.Map<Book, BookModel>(result.Book);
return Ok(BookModel);
}

[HttpDelete("{id}")]
[Authorize(Roles = "ADMINISTRADOR")]
public async Task<IActionResult> DeleteAsync(int id)
{
var result = await _booksService.DeleteAsync(id);

if (!result.Success)
return BadRequest(result.Message);

var BookModel = _mapper.Map<Book, BookModel>(result.Book);
return Ok(BookModel);
}
}
}
52 changes: 52 additions & 0 deletions LibraryAPI/API/Controllers/UsersController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
using AutoMapper;
using LibraryApi.Domain.Entities;
using LibraryApi.Domain.Services;
using LibraryApi.Extensions;
using LibraryApi.Models;
using Microsoft.AspNetCore.Mvc;

namespace LibraryApi.Controllers
{
[Route("/api/[controller]")]
public class UsersController : Controller
{
private readonly IUsersService _usersService;
private readonly IMapper _mapper;

public UsersController(IMapper mapper, IUsersService usersService)
{
_mapper = mapper;
_usersService = usersService;
}

[HttpPost]
public async Task<IActionResult> PostAsync([FromBody] SaveUserModel model)
{
if (!ModelState.IsValid)
return BadRequest(ModelState.GetErrorMessages());

var user = _mapper.Map<SaveUserModel, User>(model);
var result = await _usersService.SaveAsync(user, model.Password);

if (!result.Success)
return BadRequest(result.Message);

var userModel = _mapper.Map<User, UserModel>(result.User);
return Ok(userModel);
}

[HttpPost("/api/[controller]/login")]
public async Task<IActionResult> LoginAsync([FromBody] LoginUserModel model)
{
if (!ModelState.IsValid)
return BadRequest(ModelState.GetErrorMessages());

var result = await _usersService.LoginAsync(model);

if (!result.Success)
return BadRequest(result.Message);

return Ok(result.Token);
}
}
}
10 changes: 10 additions & 0 deletions LibraryAPI/API/Domain/Entities/Book.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespace LibraryApi.Domain.Entities
{
public class Book
{
public int Id { get; set; }
public string Name { get; set; }
public string ImageUrl { get; set; }
public string Author { get; set; }
}
}
10 changes: 10 additions & 0 deletions LibraryAPI/API/Domain/Entities/User.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespace LibraryApi.Domain.Entities
{
public class User
{
public int Id { get; set; }
public string Email { get; set; }
public string Password { get; set; }
public UserRoleEnum Role { get; set; }
}
}
13 changes: 13 additions & 0 deletions LibraryAPI/API/Domain/Entities/UserRoleEnum.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using System.ComponentModel;

namespace LibraryApi.Domain.Entities
{
public enum UserRoleEnum
{
[Description("Básico")]
BASICO = 1,

[Description("Administrador")]
ADMINISTRADOR = 2
}
}
15 changes: 15 additions & 0 deletions LibraryAPI/API/Domain/Repositories/IBooksRepository.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using LibraryApi.Domain.Entities;
using LibraryApi.Models;

namespace LibraryApi.Domain.Repositories
{
public interface IBooksRepository
{
Task<IEnumerable<Book>> ListAsync(ListBooksModel model);
Task AddAsync(Book book);
Task<Book?> FindByIdAsync(int id);
Task<Book?> FindByNameAsync(string name);
void Update(Book book);
void Remove(Book book);
}
}
7 changes: 7 additions & 0 deletions LibraryAPI/API/Domain/Repositories/IUnitOfWork.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace LibraryApi.Domain.Repositories
{
public interface IUnitOfWork
{
Task CompleteAsync();
}
}
12 changes: 12 additions & 0 deletions LibraryAPI/API/Domain/Repositories/IUsersRepository.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using LibraryApi.Domain.Entities;
using Microsoft.AspNetCore.Identity;

namespace LibraryApi.Domain.Repositories
{
public interface IUsersRepository
{
Task AddAsync(User user);
Task<User> GetUserByEmailAsync(string email);
Task<User> GetUserByEmailAndPasswordAsync(string email, string password);
}
}
14 changes: 14 additions & 0 deletions LibraryAPI/API/Domain/Services/Communication/BaseResponse.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
namespace LibraryApi.Domain.Services.Communication
{
public abstract class BaseResponse
{
public bool Success { get; protected set; }
public string Message { get; protected set; }

public BaseResponse(bool success, string message)
{
Success = success;
Message = message;
}
}
}
18 changes: 18 additions & 0 deletions LibraryAPI/API/Domain/Services/Communication/BookResponse.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using LibraryApi.Domain.Entities;

namespace LibraryApi.Domain.Services.Communication
{
public class BookResponse : BaseResponse
{
public Book Book { get; private set; }

private BookResponse(bool success, string message, Book book) : base(success, message)
{
Book = book;
}

public BookResponse(Book book) : this(true, string.Empty, book) { }

public BookResponse(string message) : this(false, message, null) { }
}
}
19 changes: 19 additions & 0 deletions LibraryAPI/API/Domain/Services/Communication/LoginResponse.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using LibraryApi.Domain.Entities;
using LibraryApi.Models;

namespace LibraryApi.Domain.Services.Communication
{
public class LoginResponse : BaseResponse
{
public JwtModel Token { get; private set; }

private LoginResponse(bool success, string message, JwtModel token) : base(success, message)
{
Token = token;
}

public LoginResponse(JwtModel token) : this(true, string.Empty, token) { }

public LoginResponse(string message) : this(false, message, null) { }
}
}
18 changes: 18 additions & 0 deletions LibraryAPI/API/Domain/Services/Communication/UserResponse.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using LibraryApi.Domain.Entities;

namespace LibraryApi.Domain.Services.Communication
{
public class UserResponse : BaseResponse
{
public User User { get; private set; }

private UserResponse(bool success, string message, User user) : base(success, message)
{
User = user;
}

public UserResponse(User user) : this(true, string.Empty, user) { }

public UserResponse(string message) : this(false, message, null) { }
}
}
14 changes: 14 additions & 0 deletions LibraryAPI/API/Domain/Services/IBooksService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using LibraryApi.Domain.Entities;
using LibraryApi.Domain.Services.Communication;
using LibraryApi.Models;

namespace LibraryApi.Domain.Services
{
public interface IBooksService
{
Task<IEnumerable<Book>> ListAsync(ListBooksModel model);
Task<BookResponse> SaveAsync(Book Book);
Task<BookResponse> UpdateAsync(int id, Book Book);
Task<BookResponse> DeleteAsync(int id);
}
}
13 changes: 13 additions & 0 deletions LibraryAPI/API/Domain/Services/IUsersService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using LibraryApi.Domain.Entities;
using LibraryApi.Domain.Services.Communication;
using LibraryApi.Models;

namespace LibraryApi.Domain.Services
{
public interface IUsersService
{
Task<UserResponse> SaveAsync(User user, string password);
Task<LoginResponse> LoginAsync(LoginUserModel user);
Task<string> GenerateToken(User user);
}
}
14 changes: 14 additions & 0 deletions LibraryAPI/API/Extensions/ModelStateExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using Microsoft.AspNetCore.Mvc.ModelBinding;

namespace LibraryApi.Extensions
{
public static class ModelStateExtensions
{
public static List<string> GetErrorMessages(this ModelStateDictionary dictionary)
{
return dictionary.SelectMany(m => m.Value.Errors)
.Select(m => m.ErrorMessage)
.ToList();
}
}
}
Loading