diff --git a/.idea/.idea.BookHive/.idea/workspace.xml b/.idea/.idea.BookHive/.idea/workspace.xml index fb89e6d..0c39774 100644 --- a/.idea/.idea.BookHive/.idea/workspace.xml +++ b/.idea/.idea.BookHive/.idea/workspace.xml @@ -6,11 +6,14 @@ - - - - + + + + + + + { @@ -98,7 +103,7 @@ @@ -127,7 +140,8 @@ diff --git a/BookHive/Endpoints/Authors/DeleteAuthorEndpoint.cs b/BookHive/Endpoints/Authors/DeleteAuthorEndpoint.cs index 2617798..3015caf 100644 --- a/BookHive/Endpoints/Authors/DeleteAuthorEndpoint.cs +++ b/BookHive/Endpoints/Authors/DeleteAuthorEndpoint.cs @@ -27,6 +27,12 @@ public class DeleteAuthorEndpoint(AuthorRepository authorRepository) : Endpoint< await Send.NotFoundAsync(ct); return; } + + if (author.Books?.Count > 0) + { + await Send.StringAsync("L'auteur possède encore des livres",409, cancellation: ct); + return; + } await authorRepository.DeleteAsync(author, ct); await Send.OkAsync(cancellation: ct); diff --git a/BookHive/Endpoints/Books/CreateBookEndpoint.cs b/BookHive/Endpoints/Books/CreateBookEndpoint.cs index f0603d0..0c916dd 100644 --- a/BookHive/Endpoints/Books/CreateBookEndpoint.cs +++ b/BookHive/Endpoints/Books/CreateBookEndpoint.cs @@ -1,11 +1,12 @@ using BookHive.DTO.Book; using BookHive.Models; using BookHive.Repositories; +using BookHive.Specifications.Authors; using FastEndpoints; namespace BookHive.Endpoints.Books; -public class CreateBookEndpoint(BookRepository bookRepository, AutoMapper.IMapper mapper) : Endpoint +public class CreateBookEndpoint(BookRepository bookRepository, AuthorRepository authorRepository, AutoMapper.IMapper mapper) : Endpoint { public override void Configure() { @@ -15,6 +16,13 @@ public class CreateBookEndpoint(BookRepository bookRepository, AutoMapper.IMappe public override async Task HandleAsync(CreateBookDto req, CancellationToken ct) { + Author? author = await authorRepository.SingleOrDefaultAsync(new GetAuthorByIdSpec(req.AuthorId), ct); + if (author is null) + { + await Send.NotFoundAsync(ct); + return; + } + await bookRepository.AddAsync(mapper.Map(req), ct); await Send.OkAsync(cancellation: ct); } diff --git a/BookHive/Endpoints/Books/DeleteBookEndpoint.cs b/BookHive/Endpoints/Books/DeleteBookEndpoint.cs index 53e9252..45d91ff 100644 --- a/BookHive/Endpoints/Books/DeleteBookEndpoint.cs +++ b/BookHive/Endpoints/Books/DeleteBookEndpoint.cs @@ -1,6 +1,7 @@ using BookHive.Models; using BookHive.Repositories; using BookHive.Specifications.Books; +using BookHive.Specifications.Loans; using FastEndpoints; namespace BookHive.Endpoints.Books; @@ -10,14 +11,14 @@ public class DeleteBookRequest public int Id { get; set; } } -public class DeleteBookEndpoint(BookRepository bookRepository) : Endpoint +public class DeleteBookEndpoint(BookRepository bookRepository, LoanRepository loanRepository) : Endpoint { public override void Configure() { Delete("/books/{@Id}", x => new { x.Id }); AllowAnonymous(); } - + public override async Task HandleAsync(DeleteBookRequest req, CancellationToken ct) { Book? book = await bookRepository.SingleOrDefaultAsync(new GetBookByIdSpec(req.Id), ct); @@ -27,7 +28,14 @@ public class DeleteBookEndpoint(BookRepository bookRepository) : Endpoint +public class CreateLoanEndpoint(LoanRepository loanRepository, BookRepository bookRepository, MemberRepository memberRepository, AutoMapper.IMapper mapper) : Endpoint { public override void Configure() { @@ -15,6 +18,39 @@ public class CreateLoanEndpoint(LoanRepository loanRepository, AutoMapper.IMappe public override async Task HandleAsync(CreateLoanDto req, CancellationToken ct) { + Book? book = await bookRepository.SingleOrDefaultAsync(new GetBookByIdSpec(req.BookId), ct); + if (book is null) + { + await Send.NotFoundAsync(ct); + return; + } + + Member? member = await memberRepository.SingleOrDefaultAsync(new GetMemberByIdSpec(req.MemberId), ct); + if (member is null) + { + await Send.NotFoundAsync(ct); + return; + } + + if (!member.IsActive) + { + await Send.StringAsync("Le membre est désactivé", 400, cancellation: ct); + return; + } + + Loan? loan = await loanRepository.FirstOrDefaultAsync(new GetAvailableBookByIdSpec(req.BookId), ct); + if (loan is not null) + { + await Send.StringAsync("Ce livre est déjà emprunté", 400, cancellation: ct); + return; + } + + if (req.DueDate < req.LoanDate || req.DueDate.DayNumber - req.LoanDate.DayNumber < 1 || req.DueDate.DayNumber - req.LoanDate.DayNumber > 30) + { + await Send.StringAsync("La date de retour estimée est incorrecte", 400, cancellation: ct); + return; + } + await loanRepository.AddAsync(mapper.Map(req), ct); await Send.OkAsync(cancellation: ct); } diff --git a/BookHive/Endpoints/Reviews/CreateReviewEndpoint.cs b/BookHive/Endpoints/Reviews/CreateReviewEndpoint.cs index 8e6f29c..ce15647 100644 --- a/BookHive/Endpoints/Reviews/CreateReviewEndpoint.cs +++ b/BookHive/Endpoints/Reviews/CreateReviewEndpoint.cs @@ -3,6 +3,7 @@ using BookHive.Models; using BookHive.Repositories; using BookHive.Specifications.Books; using BookHive.Specifications.Members; +using BookHive.Specifications.Reviews; using FastEndpoints; namespace BookHive.Endpoints.Reviews; @@ -36,6 +37,19 @@ public class CreateReviewEndpoint( return; } + if (!member.IsActive) + { + await Send.StringAsync("Le membre est désactivé", 400, cancellation: ct); + return; + } + + Review? review = await reviewRepository.SingleOrDefaultAsync(new GetReviewByCriteriaSpec(req.BookId, req.MemberId), ct); + if (review is not null) + { + await Send.StringAsync("Le membre a déjà posté un commentaire", 400, cancellation: ct); + return; + } + await reviewRepository.AddAsync(mapper.Map(req), ct); await Send.OkAsync(cancellation: ct); } diff --git a/BookHive/Specifications/Loans/GetAvailableBookByIdSpec.cs b/BookHive/Specifications/Loans/GetAvailableBookByIdSpec.cs new file mode 100644 index 0000000..fe7224b --- /dev/null +++ b/BookHive/Specifications/Loans/GetAvailableBookByIdSpec.cs @@ -0,0 +1,13 @@ +using Ardalis.Specification; +using BookHive.Models; + +namespace BookHive.Specifications.Loans; + +public class GetAvailableBookByIdSpec : Specification +{ + public GetAvailableBookByIdSpec(int bookId) + { + Query + .Where(x => x.BookId == bookId && x.ReturnDate == null); + } +} \ No newline at end of file diff --git a/BookHive/Specifications/Reviews/GetReviewByCriteriaSpec.cs b/BookHive/Specifications/Reviews/GetReviewByCriteriaSpec.cs new file mode 100644 index 0000000..23753a0 --- /dev/null +++ b/BookHive/Specifications/Reviews/GetReviewByCriteriaSpec.cs @@ -0,0 +1,13 @@ +using Ardalis.Specification; +using BookHive.Models; + +namespace BookHive.Specifications.Reviews; + +public class GetReviewByCriteriaSpec : SingleResultSpecification +{ + public GetReviewByCriteriaSpec(int bookId, int memberId) + { + Query + .Where(x => x.BookId == bookId && x.MemberId == memberId); + } +} \ No newline at end of file