diff --git a/ShareBook/ShareBook.Api/Controllers/BookController.cs b/ShareBook/ShareBook.Api/Controllers/BookController.cs index 49feaa48..c3dfd244 100644 --- a/ShareBook/ShareBook.Api/Controllers/BookController.cs +++ b/ShareBook/ShareBook.Api/Controllers/BookController.cs @@ -69,6 +69,15 @@ public PagedList Paged(int page, int items) [AuthorizationFilter(Permissions.Permission.ApproveBook)] public Result Approve(string id, [FromBody] ApproveBookVM model) => _service.Approve(new Guid(id), model?.ChooseDate); + [Authorize("Bearer")] + [HttpPost("Cancel/{id}")] + public Result Cancel(string id) => _service.Cancel(new Guid(id), false); + + [Authorize("Bearer")] + [HttpPost("CancelAdmin/{id}")] + [AuthorizationFilter(Permissions.Permission.DonateBook)] + public Result CancelAdmin(string id) => _service.Cancel(new Guid(id), true); + [HttpGet("FreightOptions")] public IList FreightOptions() { diff --git a/ShareBook/ShareBook.Domain/Book.cs b/ShareBook/ShareBook.Domain/Book.cs index 1f8b95bd..9b748717 100644 --- a/ShareBook/ShareBook.Domain/Book.cs +++ b/ShareBook/ShareBook.Domain/Book.cs @@ -37,6 +37,8 @@ public class Book : BaseEntity public bool Approved { get; set; } = false; + public bool Canceled { get; set; } = false; + public virtual ICollection BookUsers { get; set; } public string ImageUrl { get; set; } @@ -55,6 +57,9 @@ public BookStatus Status() if (Donated()) return BookStatus.Donated; + if(Canceled) + return BookStatus.Canceled; + if (Approved) return BookStatus.Available; diff --git a/ShareBook/ShareBook.Domain/Enums/BookStatus.cs b/ShareBook/ShareBook.Domain/Enums/BookStatus.cs index 7c56fe85..1b4cfbda 100644 --- a/ShareBook/ShareBook.Domain/Enums/BookStatus.cs +++ b/ShareBook/ShareBook.Domain/Enums/BookStatus.cs @@ -15,6 +15,8 @@ public enum BookStatus [Description("Invisível")] Invisible, [Description("Doado")] - Donated + Donated, + [Description("Cancelado")] + Canceled } } diff --git a/ShareBook/ShareBook.Repository/Migrations/20181221233828_NewField_Book_Canceled.Designer.cs b/ShareBook/ShareBook.Repository/Migrations/20181221233828_NewField_Book_Canceled.Designer.cs new file mode 100644 index 00000000..8ae7e4d7 --- /dev/null +++ b/ShareBook/ShareBook.Repository/Migrations/20181221233828_NewField_Book_Canceled.Designer.cs @@ -0,0 +1,279 @@ +// +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage; +using Microsoft.EntityFrameworkCore.Storage.Internal; +using ShareBook.Domain.Enums; +using ShareBook.Repository; +using System; + +namespace ShareBook.Repository.Migrations +{ + [DbContext(typeof(ApplicationDbContext))] + [Migration("20181221233828_NewField_Book_Canceled")] + partial class NewField_Book_Canceled + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "2.0.3-rtm-10026") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + modelBuilder.Entity("ShareBook.Domain.Address", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("City") + .HasColumnType("varchar(30)") + .HasMaxLength(30); + + b.Property("Complement") + .HasColumnType("varchar(30)") + .HasMaxLength(30); + + b.Property("Country") + .HasColumnType("varchar(30)") + .HasMaxLength(30); + + b.Property("CreationDate"); + + b.Property("Neighborhood") + .HasColumnType("varchar(30)") + .HasMaxLength(30); + + b.Property("Number") + .HasColumnType("varchar(10)") + .HasMaxLength(10); + + b.Property("PostalCode") + .HasColumnType("varchar(15)") + .HasMaxLength(15); + + b.Property("State") + .HasColumnType("varchar(30)") + .HasMaxLength(30); + + b.Property("Street") + .HasColumnType("varchar(50)") + .HasMaxLength(50); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("Addresses"); + }); + + modelBuilder.Entity("ShareBook.Domain.Book", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Approved"); + + b.Property("Author") + .IsRequired() + .HasColumnType("varchar(200)") + .HasMaxLength(50); + + b.Property("Canceled"); + + b.Property("CategoryId"); + + b.Property("ChooseDate"); + + b.Property("CreationDate"); + + b.Property("FreightOption"); + + b.Property("ImageSlug") + .IsRequired() + .HasColumnType("varchar(100)") + .HasMaxLength(100); + + b.Property("Slug") + .HasColumnType("varchar(100)") + .HasMaxLength(100); + + b.Property("Synopsis") + .HasColumnType("varchar(2000)") + .HasMaxLength(2000); + + b.Property("Title") + .IsRequired() + .HasColumnType("varchar(200)") + .HasMaxLength(50); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("CategoryId"); + + b.HasIndex("UserId"); + + b.ToTable("Books"); + }); + + modelBuilder.Entity("ShareBook.Domain.BookUser", b => + { + b.Property("Id"); + + b.Property("BookId"); + + b.Property("UserId"); + + b.Property("CreationDate"); + + b.Property("Note") + .HasColumnType("varchar(2000)") + .HasMaxLength(2000); + + b.Property("Reason") + .HasColumnType("varchar(2000)") + .HasMaxLength(2000); + + b.Property("Status"); + + b.HasKey("Id", "BookId", "UserId"); + + b.HasIndex("BookId"); + + b.HasIndex("UserId"); + + b.ToTable("BookUser"); + }); + + modelBuilder.Entity("ShareBook.Domain.Category", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("CreationDate"); + + b.Property("Name") + .IsRequired() + .HasColumnType("varchar(100)") + .HasMaxLength(100); + + b.HasKey("Id"); + + b.ToTable("Categories"); + }); + + modelBuilder.Entity("ShareBook.Domain.LogEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("CreationDate"); + + b.Property("EntityId"); + + b.Property("EntityName"); + + b.Property("LogDateTime"); + + b.Property("Operation"); + + b.Property("UserId"); + + b.Property("ValuesChanges"); + + b.HasKey("Id"); + + b.ToTable("LogEntries"); + }); + + modelBuilder.Entity("ShareBook.Domain.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("CreationDate"); + + b.Property("Email") + .IsRequired() + .HasColumnType("varchar(100)") + .HasMaxLength(100); + + b.Property("HashCodePassword") + .HasColumnType("varchar(200)") + .HasMaxLength(200); + + b.Property("HashCodePasswordExpiryDate") + .HasColumnType("datetime2(7)"); + + b.Property("Linkedin") + .HasColumnType("varchar(100)") + .HasMaxLength(100); + + b.Property("Name") + .IsRequired() + .HasColumnType("varchar(200)") + .HasMaxLength(100); + + b.Property("Password") + .IsRequired() + .HasColumnType("varchar(50)") + .HasMaxLength(50); + + b.Property("PasswordSalt") + .IsRequired() + .HasColumnType("varchar(50)") + .HasMaxLength(50); + + b.Property("Phone") + .HasColumnType("varchar(30)") + .HasMaxLength(30); + + b.Property("Profile"); + + b.HasKey("Id"); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("ShareBook.Domain.Address", b => + { + b.HasOne("ShareBook.Domain.User") + .WithOne("Address") + .HasForeignKey("ShareBook.Domain.Address", "UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("ShareBook.Domain.Book", b => + { + b.HasOne("ShareBook.Domain.Category", "Category") + .WithMany() + .HasForeignKey("CategoryId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ShareBook.Domain.User", "User") + .WithMany() + .HasForeignKey("UserId"); + }); + + modelBuilder.Entity("ShareBook.Domain.BookUser", b => + { + b.HasOne("ShareBook.Domain.Book", "Book") + .WithMany("BookUsers") + .HasForeignKey("BookId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ShareBook.Domain.User", "User") + .WithMany("BookUsers") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/ShareBook/ShareBook.Repository/Migrations/20181221233828_NewField_Book_Canceled.cs b/ShareBook/ShareBook.Repository/Migrations/20181221233828_NewField_Book_Canceled.cs new file mode 100644 index 00000000..e4cc3263 --- /dev/null +++ b/ShareBook/ShareBook.Repository/Migrations/20181221233828_NewField_Book_Canceled.cs @@ -0,0 +1,25 @@ +using Microsoft.EntityFrameworkCore.Migrations; +using System; +using System.Collections.Generic; + +namespace ShareBook.Repository.Migrations +{ + public partial class NewField_Book_Canceled : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "Canceled", + table: "Books", + nullable: false, + defaultValue: false); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "Canceled", + table: "Books"); + } + } +} diff --git a/ShareBook/ShareBook.Repository/Migrations/ApplicationDbContextModelSnapshot.cs b/ShareBook/ShareBook.Repository/Migrations/ApplicationDbContextModelSnapshot.cs index 64f77593..38982275 100644 --- a/ShareBook/ShareBook.Repository/Migrations/ApplicationDbContextModelSnapshot.cs +++ b/ShareBook/ShareBook.Repository/Migrations/ApplicationDbContextModelSnapshot.cs @@ -82,6 +82,8 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasColumnType("varchar(200)") .HasMaxLength(50); + b.Property("Canceled"); + b.Property("CategoryId"); b.Property("ChooseDate"); diff --git a/ShareBook/ShareBook.Service/Book/BookService.cs b/ShareBook/ShareBook.Service/Book/BookService.cs index 9234ea6a..ac086766 100644 --- a/ShareBook/ShareBook.Service/Book/BookService.cs +++ b/ShareBook/ShareBook.Service/Book/BookService.cs @@ -24,7 +24,7 @@ public class BookService : BaseService, IBookService private readonly IUploadService _uploadService; private readonly IBooksEmailService _booksEmailService; - public BookService(IBookRepository bookRepository, +public BookService(IBookRepository bookRepository, IUnitOfWork unitOfWork, IValidator validator, IUploadService uploadService, IBooksEmailService booksEmailService) : base(bookRepository, unitOfWork, validator) @@ -48,6 +48,27 @@ public Result Approve(Guid bookId, DateTime? chooseDate = null) return new Result(book); } + public Result Cancel(Guid bookId, bool isAdmin = false) + { + var book = _repository.Get().Include(x => x.BookUsers).FirstOrDefault(x => x.Id == bookId); + + if (book == null) + throw new ShareBookException(ShareBookException.Error.NotFound); + + if (!isAdmin && book.BookUsers != null && book.BookUsers.Count > 0) + throw new ShareBookException("Este livro já possui interessados"); + + book.Approved = false; + book.ChooseDate = null; + book.Canceled = true; + + _repository.Update(book); + + _booksEmailService.SendEmailBookCanceledToAdmins(book).Wait(); + + return new Result(book); + } + public void HideBook(Guid bookId) { var book = _repository.Find(bookId); @@ -131,10 +152,10 @@ public override Result Update(Book entity) var bookAlreadyApproved = BookAlreadyApproved(bookId); if (!result.Success) return result; - + if(!bookAlreadyApproved) entity.Slug = SetSlugByTitleOrIncremental(entity); - + //imagem eh opcional no update if (entity.ImageName != "" && entity.ImageBytes.Length > 0) @@ -155,7 +176,7 @@ public override Result Update(Book entity) return result; } - + public PagedList ByTitle(string title, int page, int itemsPerPage) => SearchBooks(x => (x.Approved diff --git a/ShareBook/ShareBook.Service/Book/BooksEmailService.cs b/ShareBook/ShareBook.Service/Book/BooksEmailService.cs index b19354ea..b2f5a4e2 100644 --- a/ShareBook/ShareBook.Service/Book/BooksEmailService.cs +++ b/ShareBook/ShareBook.Service/Book/BooksEmailService.cs @@ -11,6 +11,8 @@ public class BooksEmailService : IBooksEmailService private const string WaitingApprovalTitle = "Aguarde aprovação do livro - Sharebook"; private const string BookApprovedTemplate = "BookApprovedTemplate"; private const string BookApprovedTitle = "Livro aprovado - Sharebook"; + private const string BookCanceledTemplate = "BookCanceledTemplate"; + private const string BookCanceledTitle = "Livro cancelado - Sharebook"; private readonly IEmailService _emailService; private readonly IUserService _userService; @@ -48,6 +50,12 @@ public async Task SendEmailNewBookInserted(Book book) await SendEmailWaitingApprovalToUser(book); } + public async Task SendEmailBookCanceledToAdmins(Book book) + { + var html = await _emailTemplate.GenerateHtmlFromTemplateAsync(BookCanceledTemplate, book); + await _emailService.SendToAdmins(html, BookCanceledTitle); + } + private async Task SendEmailNewBookInsertedToAdministrators(Book book) { var html = await _emailTemplate.GenerateHtmlFromTemplateAsync(NewBookInsertedTemplate, book); diff --git a/ShareBook/ShareBook.Service/Book/IBookService.cs b/ShareBook/ShareBook.Service/Book/IBookService.cs index d2bafd2e..73c49ff7 100644 --- a/ShareBook/ShareBook.Service/Book/IBookService.cs +++ b/ShareBook/ShareBook.Service/Book/IBookService.cs @@ -10,6 +10,8 @@ public interface IBookService : IBaseService { Result Approve(Guid bookId, DateTime? chooseDate); + Result Cancel(Guid bookId, bool isAdmin = false); + void HideBook(Guid bookId); IList FreightOptions(); diff --git a/ShareBook/ShareBook.Service/Book/IBooksEmailService.cs b/ShareBook/ShareBook.Service/Book/IBooksEmailService.cs index 8a4eae47..412aaed4 100644 --- a/ShareBook/ShareBook.Service/Book/IBooksEmailService.cs +++ b/ShareBook/ShareBook.Service/Book/IBooksEmailService.cs @@ -8,5 +8,7 @@ public interface IBooksEmailService Task SendEmailNewBookInserted(Book book); Task SendEmailBookApproved(Book book); + + Task SendEmailBookCanceledToAdmins(Book book); } } \ No newline at end of file diff --git a/ShareBook/ShareBook.Service/Email/Templates/BookCanceledTemplate.html b/ShareBook/ShareBook.Service/Email/Templates/BookCanceledTemplate.html new file mode 100644 index 00000000..845cbe26 --- /dev/null +++ b/ShareBook/ShareBook.Service/Email/Templates/BookCanceledTemplate.html @@ -0,0 +1,22 @@ + + + + + Livro cancelado pelo doador - Sharebook + + +

+ Olá Administrador(a), +

+

+ Um livro foi cancelado pelo doador. Veja mais informações abaixo: +

+ +
    +
  • Livro: {Title}
  • +
  • Autor: {Author}
  • +
+ +

Sharebook

+ + \ No newline at end of file diff --git a/ShareBook/ShareBook.Service/ShareBook.Service.csproj b/ShareBook/ShareBook.Service/ShareBook.Service.csproj index 717230aa..a31fe0f0 100644 --- a/ShareBook/ShareBook.Service/ShareBook.Service.csproj +++ b/ShareBook/ShareBook.Service/ShareBook.Service.csproj @@ -21,6 +21,9 @@ PreserveNewest + + PreserveNewest + PreserveNewest