From 8d6986fcc7dee520ed7d235bb45df9df61b9a84a Mon Sep 17 00:00:00 2001 From: Henrique Holtz Date: Tue, 11 Jun 2024 19:33:04 -0300 Subject: [PATCH 01/37] perf: IBooksEmailService. IBookService => Turning some methods as async --- .../Controllers/BookController.cs | 12 ++++---- .../ShareBook.Service/Book/BookService.cs | 28 +++++++++---------- .../Book/BooksEmailService.cs | 11 ++++---- .../ShareBook.Service/Book/IBookService.cs | 6 ++-- .../Book/IBooksEmailService.cs | 7 ++--- .../BookUser/BookUserService.cs | 17 +++++------ .../BookUser/IBookUserService.cs | 2 +- .../ShareBook.Service/Email/IEmailService.cs | 1 - .../ShareBook.Service/Upload/UploadService.cs | 6 +--- 9 files changed, 42 insertions(+), 48 deletions(-) diff --git a/ShareBook/ShareBook.Api/Controllers/BookController.cs b/ShareBook/ShareBook.Api/Controllers/BookController.cs index 435d1cde..a7e8f518 100644 --- a/ShareBook/ShareBook.Api/Controllers/BookController.cs +++ b/ShareBook/ShareBook.Api/Controllers/BookController.cs @@ -78,18 +78,18 @@ public PagedList Paged(int page, int items) [Authorize("Bearer")] [HttpPost("Approve/{id}")] [AuthorizationFilter(Permissions.Permission.ApproveBook)] - public Result Approve(string id, [FromBody] ApproveBookVM model) + public async Task ApproveAsync(string id, [FromBody] ApproveBookVM model) { - _service.Approve(new Guid(id), model?.ChooseDate); + await _service.ApproveAsync(new Guid(id), model?.ChooseDate); return new Result("Livro aprovado com sucesso."); } [Authorize("Bearer")] [HttpPost("Received/{bookId}")] - public Result Received(string bookId) + public async Task ReceivedAsync(string bookId) { Guid winnerUserId = new Guid(Thread.CurrentPrincipal?.Identity?.Name); - _service.Received(new Guid(bookId), winnerUserId); + await _service.ReceivedAsync(new Guid(bookId), winnerUserId); return new Result("Livro Recebido com sucesso."); } @@ -284,11 +284,11 @@ public IActionResult Update(Guid Id, [FromBody] UpdateBookVM updateBookVM) [Authorize("Bearer")] [HttpPut("Donate/{bookId}")] [ProducesResponseType(typeof(Result), 200)] - public IActionResult DonateBook(Guid bookId, [FromBody] DonateBookUserVM donateBookUserVM) + public async Task DonateBookAsync(Guid bookId, [FromBody] DonateBookUserVM donateBookUserVM) { if (!_IsBookOwner(bookId)) return Unauthorized(); - _bookUserService.DonateBook(bookId, donateBookUserVM.UserId, donateBookUserVM.Note); + await _bookUserService.DonateBookAsync(bookId, donateBookUserVM.UserId, donateBookUserVM.Note); var result = new Result { diff --git a/ShareBook/ShareBook.Service/Book/BookService.cs b/ShareBook/ShareBook.Service/Book/BookService.cs index f4ac2037..ce1c2794 100644 --- a/ShareBook/ShareBook.Service/Book/BookService.cs +++ b/ShareBook/ShareBook.Service/Book/BookService.cs @@ -44,20 +44,20 @@ public BookService(IBookRepository bookRepository, _newBookQueue = newBookQueue; } - public void Approve(Guid bookId, DateTime? chooseDate = null) + public async Task ApproveAsync(Guid bookId, DateTime? chooseDate = null) { var daysInShowcase = int.Parse(_configuration["SharebookSettings:DaysInShowcase"]); - var book = _repository.Get().Include(b => b.Category).FirstOrDefault(b => b.Id == bookId); + var book = await _repository.Get().Include(b => b.Category).FirstOrDefaultAsync(b => b.Id == bookId); if (book == null) throw new ShareBookException(ShareBookException.Error.NotFound); book.Status = BookStatus.Available; book.ChooseDate = chooseDate?.Date ?? DateTime.Today.AddDays(daysInShowcase); - _repository.Update(book); + await _repository.UpdateAsync(book); // notifica o doador - _booksEmailService.SendEmailBookApproved(book).Wait(); + await _booksEmailService.SendEmailBookApprovedAsync(book); // notifica possíveis interessados. var message = new NewBookBody{ @@ -65,15 +65,15 @@ public void Approve(Guid bookId, DateTime? chooseDate = null) BookTitle = book.Title, CategoryId = book.CategoryId }; - _newBookQueue.SendMessage(message).Wait(); + await _newBookQueue.SendMessage(message); } - public void Received(Guid bookId, Guid winnerUserId) + public async Task ReceivedAsync(Guid bookId, Guid winnerUserId) { - var book = _repository.Get().Include(f => f.BookUsers) + var book = await _repository.Get().Include(f => f.BookUsers) .ThenInclude(bu => bu.User) - .FirstOrDefault(f => f.Id == bookId); + .FirstOrDefaultAsync(f => f.Id == bookId); if (book == null) throw new ShareBookException(ShareBookException.Error.NotFound); @@ -84,19 +84,19 @@ public void Received(Guid bookId, Guid winnerUserId) throw new ShareBookException(ShareBookException.Error.Forbidden); book.Status = BookStatus.Received; - _repository.Update(book); + await _repository.UpdateAsync(book); - _booksEmailService.SendEmailBookReceived(book); + await _booksEmailService.SendEmailBookReceivedAsync(book); } - public void UpdateBookStatus(Guid bookId, BookStatus bookStatus) + public async Task UpdateBookStatusAsync(Guid bookId, BookStatus bookStatus) { - var book = _repository.Find(bookId); + var book = await _repository.FindAsync(bookId); if (book == null) throw new ShareBookException(ShareBookException.Error.NotFound); book.Status = bookStatus; - _repository.Update(book); + await _repository.UpdateAsync(book); } public IList FreightOptions() @@ -206,7 +206,7 @@ public override Result Insert(Book entity) result.Value.ImageBytes = null; - _booksEmailService.SendEmailNewBookInserted(entity).Wait(); + _booksEmailService.SendEmailNewBookInsertedAsync(entity).Wait(); } return result; } diff --git a/ShareBook/ShareBook.Service/Book/BooksEmailService.cs b/ShareBook/ShareBook.Service/Book/BooksEmailService.cs index 509bb044..0c6a3f34 100644 --- a/ShareBook/ShareBook.Service/Book/BooksEmailService.cs +++ b/ShareBook/ShareBook.Service/Book/BooksEmailService.cs @@ -36,7 +36,7 @@ public BooksEmailService( _emailTemplate = emailTemplate; } - public async Task SendEmailBookApproved(Book book) + public async Task SendEmailBookApprovedAsync(Book book) { if (book.User == null) book.User = _userService.Find(book.UserId); @@ -54,7 +54,7 @@ public async Task SendEmailBookApproved(Book book) } } - public void SendEmailBookReceived(Book book) + public async Task SendEmailBookReceivedAsync(Book book) { if (book.User == null) book.User = _userService.Find(book.UserId); @@ -68,13 +68,12 @@ public void SendEmailBookReceived(Book book) WinnerName = book.WinnerName(), }; - // TODO: Remove "GetAwaiter().GetResult()" - var htmt = _emailTemplate.GenerateHtmlFromTemplateAsync(BookReceivedTemplate, vm).GetAwaiter().GetResult(); - _emailService.Send(book.User.Email, book.User.Name, htmt, BookReceivedTemplate, copyAdmins: true, highPriority: true); + var htmt = await _emailTemplate.GenerateHtmlFromTemplateAsync(BookReceivedTemplate, vm); + await _emailService.Send(book.User.Email, book.User.Name, htmt, BookReceivedTemplate, copyAdmins: true, highPriority: true); } } - public async Task SendEmailNewBookInserted(Book book) + public async Task SendEmailNewBookInsertedAsync(Book book) { if (book.User == null) book.User = _userService.Find(book.UserId); diff --git a/ShareBook/ShareBook.Service/Book/IBookService.cs b/ShareBook/ShareBook.Service/Book/IBookService.cs index c2a061cd..df61057e 100644 --- a/ShareBook/ShareBook.Service/Book/IBookService.cs +++ b/ShareBook/ShareBook.Service/Book/IBookService.cs @@ -11,10 +11,10 @@ namespace ShareBook.Service { public interface IBookService : IBaseService { - void Approve(Guid bookId, DateTime? chooseDate); + Task ApproveAsync(Guid bookId, DateTime? chooseDate); - void Received(Guid bookId, Guid winnerUserId); - void UpdateBookStatus(Guid bookId, BookStatus bookStatus); + Task ReceivedAsync(Guid bookId, Guid winnerUserId); + Task UpdateBookStatusAsync(Guid bookId, BookStatus bookStatus); IList FreightOptions(); diff --git a/ShareBook/ShareBook.Service/Book/IBooksEmailService.cs b/ShareBook/ShareBook.Service/Book/IBooksEmailService.cs index f436067d..a601df70 100644 --- a/ShareBook/ShareBook.Service/Book/IBooksEmailService.cs +++ b/ShareBook/ShareBook.Service/Book/IBooksEmailService.cs @@ -5,11 +5,10 @@ namespace ShareBook.Service { public interface IBooksEmailService { - Task SendEmailNewBookInserted(Book book); + Task SendEmailNewBookInsertedAsync(Book book); - Task SendEmailBookApproved(Book book); - - void SendEmailBookReceived(Book book); + Task SendEmailBookApprovedAsync(Book book); + Task SendEmailBookReceivedAsync(Book book); } } \ No newline at end of file diff --git a/ShareBook/ShareBook.Service/BookUser/BookUserService.cs b/ShareBook/ShareBook.Service/BookUser/BookUserService.cs index 5d850ebb..374af0c7 100644 --- a/ShareBook/ShareBook.Service/BookUser/BookUserService.cs +++ b/ShareBook/ShareBook.Service/BookUser/BookUserService.cs @@ -104,20 +104,20 @@ private void MaxRequestsValidation(Book bookRequested) _bookUsersEmailService.SendEmailMaxRequests(bookRequested); } - public void DonateBook(Guid bookId, Guid userId, string note) + public async Task DonateBookAsync(Guid bookId, Guid userId, string note) { var book = _bookService.Find(bookId); if (!book.MayChooseWinner()) throw new ShareBookException(ShareBookException.Error.BadRequest, "Aguarde a data de decisão."); - var bookUserAccepted = _bookUserRepository.Get() + var bookUserAccepted = await _bookUserRepository.Get() .Include(u => u.Book).ThenInclude(b => b.UserFacilitator) .Include(u => u.Book).ThenInclude(b => b.User) .Include(u => u.User).ThenInclude(u => u.Address) .Where(x => x.UserId == userId && x.BookId == bookId && x.Status == DonationStatus.WaitingAction) - .FirstOrDefault(); + .FirstOrDefaultAsync(); if (bookUserAccepted == null) throw new ShareBookException("Não existe a relação de usuário e livro para a doação."); @@ -127,23 +127,23 @@ public void DonateBook(Guid bookId, Guid userId, string note) bookUserAccepted.UpdateBookUser(DonationStatus.Donated, note); - _bookUserRepository.Update(bookUserAccepted); + await _bookUserRepository.UpdateAsync(bookUserAccepted); DeniedBookUsers(bookId); - _bookService.UpdateBookStatus(bookId, BookStatus.WaitingSend); + await _bookService.UpdateBookStatusAsync(bookId, BookStatus.WaitingSend); // usamos await nas notificações porque eventualmente tem risco da taks // não completar o trabalho dela. Talvez tenha a ver com o garbage collector. // avisa o ganhador - _bookUsersEmailService.SendEmailBookDonated(bookUserAccepted).Wait(); + await _bookUsersEmailService.SendEmailBookDonated(bookUserAccepted); // avisa os perdedores :/ - NotifyInterestedAboutBooksWinner(bookId).Wait(); + await NotifyInterestedAboutBooksWinner(bookId); // avisa o doador - _bookUsersEmailService.SendEmailBookDonatedNotifyDonor(bookUserAccepted.Book, bookUserAccepted.User).Wait(); + await _bookUsersEmailService.SendEmailBookDonatedNotifyDonor(bookUserAccepted.Book, bookUserAccepted.User); } public Result Cancel(BookCancelationDTO dto) @@ -151,6 +151,7 @@ public Result Cancel(BookCancelationDTO dto) if (dto.Book == null) throw new ShareBookException(ShareBookException.Error.NotFound); + // TODO: Migrate to "ToListAsync" var bookUsers = _bookUserRepository.Get().Where(x => x.BookId == dto.Book.Id).ToList(); dto.Book.ChooseDate = null; diff --git a/ShareBook/ShareBook.Service/BookUser/IBookUserService.cs b/ShareBook/ShareBook.Service/BookUser/IBookUserService.cs index fa000e10..a10156fa 100644 --- a/ShareBook/ShareBook.Service/BookUser/IBookUserService.cs +++ b/ShareBook/ShareBook.Service/BookUser/IBookUserService.cs @@ -15,7 +15,7 @@ public interface IBookUserService IList GetRequestersList(Guid bookId); - void DonateBook(Guid bookId, Guid userId, string note); + Task DonateBookAsync(Guid bookId, Guid userId, string note); void DeniedBookUsers(Guid bookId); diff --git a/ShareBook/ShareBook.Service/Email/IEmailService.cs b/ShareBook/ShareBook.Service/Email/IEmailService.cs index bf9e4a40..9b55c115 100644 --- a/ShareBook/ShareBook.Service/Email/IEmailService.cs +++ b/ShareBook/ShareBook.Service/Email/IEmailService.cs @@ -1,5 +1,4 @@ using ShareBook.Domain; -using ShareBook.Service.AwsSqs.Dto; using System.Collections.Generic; using System.Threading.Tasks; diff --git a/ShareBook/ShareBook.Service/Upload/UploadService.cs b/ShareBook/ShareBook.Service/Upload/UploadService.cs index 64290be3..162c23af 100644 --- a/ShareBook/ShareBook.Service/Upload/UploadService.cs +++ b/ShareBook/ShareBook.Service/Upload/UploadService.cs @@ -29,11 +29,7 @@ public async Task UploadImageAsync(byte[] imageBytes, string imageName, { var dinamicDirectory = Path.Combine(_imageSettings.ImagePath, lastDirectory); - var directoryBase = AppDomain.CurrentDomain.BaseDirectory + dinamicDirectory; - - var testPath = Path.Combine(directoryBase, imageName); - - UploadFileAsync(imageBytes, imageName, dinamicDirectory); + await UploadFileAsync(imageBytes, imageName, dinamicDirectory); return GetImageUrl(imageName, lastDirectory); } From 0740808210ad347965a5006e5abcf19dcf746ebf Mon Sep 17 00:00:00 2001 From: Henrique Holtz Date: Wed, 12 Jun 2024 07:58:59 -0300 Subject: [PATCH 02/37] perf: Turning a lot of methods as async (IBookService, IBookUserService, ILgpdService, IUserService) and its endpoints --- .../Controllers/AccountController.cs | 24 ++--- .../Controllers/BookController.cs | 100 +++++++++--------- .../Controllers/Generic/BaseCRUDController.cs | 13 +-- .../Controllers/Generic/BaseController.cs | 3 +- .../Generic/BaseDeleteController.cs | 3 +- .../ShareBook.Service/Book/BookService.cs | 69 ++++++------ .../Book/BooksEmailService.cs | 6 +- .../ShareBook.Service/Book/IBookService.cs | 12 +-- .../BookUser/BookUserEmailService.cs | 6 +- .../BookUser/BookUserService.cs | 80 +++++++------- .../BookUser/IBookUserService.cs | 12 +-- .../ShareBook.Service/Generic/BaseService.cs | 38 +++---- .../ShareBook.Service/Generic/IBaseService.cs | 15 +-- .../ShareBook.Service/Lgpd/ILgpdService.cs | 3 +- .../ShareBook.Service/Lgpd/LgpdService.cs | 19 ++-- .../ShareBook.Service/User/IUserService.cs | 3 +- .../ShareBook.Service/User/UserService.cs | 16 +-- .../Services/BookServiceTests.cs | 21 ++-- .../Services/UserServiceTests.cs | 30 +++--- .../Jobs/0 - CancelAbandonedDonations.cs | 3 +- .../Jobs/2 - LateDonationNotification.cs | 2 +- .../Jobs/3 - RemoveBookFromShowcase.cs | 3 +- .../Jobs/5 - NewBookGetInterestedUsers.cs | 2 +- 23 files changed, 243 insertions(+), 240 deletions(-) diff --git a/ShareBook/ShareBook.Api/Controllers/AccountController.cs b/ShareBook/ShareBook.Api/Controllers/AccountController.cs index 08ecefb1..05e66e1e 100644 --- a/ShareBook/ShareBook.Api/Controllers/AccountController.cs +++ b/ShareBook/ShareBook.Api/Controllers/AccountController.cs @@ -53,10 +53,10 @@ public AccountController(IUserService userService, [HttpGet] [Authorize("Bearer")] - public UserVM Get() + public async Task GetAsync() { var id = new Guid(Thread.CurrentPrincipal?.Identity?.Name); - var user = _userService.Find(id); + var user = await _userService.FindAsync(id); var userVM = _mapper.Map(user); return userVM; @@ -64,10 +64,10 @@ public UserVM Get() [Authorize("Bearer")] [HttpGet("Profile")] - public object Profile() + public async Task ProfileAsync() { var id = new Guid(Thread.CurrentPrincipal?.Identity?.Name); - return new { profile = _userService.Find(id).Profile.ToString() }; + return new { profile = (await _userService.FindAsync(id)).Profile.ToString() }; } [Authorize("Bearer")] @@ -172,13 +172,13 @@ public IActionResult ForgotMyPassword([FromBody] ForgotMyPasswordVM forgotMyPass [HttpPost("Anonymize")] [Authorize("Bearer")] - public IActionResult Anonymize([FromBody] UserAnonymizeDTO dto) + public async Task AnonymizeAsync([FromBody] UserAnonymizeDTO dto) { var userIdFromSession = new Guid(Thread.CurrentPrincipal?.Identity?.Name); if(dto.UserId != userIdFromSession) throw new ShareBookException(ShareBookException.Error.Forbidden, "Você não tem permissão para remover esse conta."); - _lgpdService.Anonymize(dto); + await _lgpdService.AnonymizeAsync(dto); return Ok(new Result("Sua conta foi removida com sucesso.")); } @@ -190,7 +190,7 @@ public IActionResult Anonymize([FromBody] UserAnonymizeDTO dto) [Authorize("Bearer")] [ProducesResponseType(typeof(Result), 200)] [ProducesResponseType(409)] - public IActionResult Update([FromBody] UpdateUserVM updateUserVM, [FromServices] SigningConfigurations signingConfigurations, [FromServices] TokenConfigurations tokenConfigurations) + public async Task UpdateAsync([FromBody] UpdateUserVM updateUserVM, [FromServices] SigningConfigurations signingConfigurations, [FromServices] TokenConfigurations tokenConfigurations) { if (!ModelState.IsValid) return BadRequest(ModelState); @@ -199,7 +199,7 @@ public IActionResult Update([FromBody] UpdateUserVM updateUserVM, [FromServices] user.Id = new Guid(Thread.CurrentPrincipal?.Identity?.Name); - var result = _userService.Update(user); + var result = await _userService.UpdateAsync(user); if (!result.Success) return Conflict(result); @@ -219,13 +219,13 @@ public Result ChangePassword([FromBody] ChangePasswordUserVM changePasswor [HttpPut("ChangeUserPasswordByHashCode")] [ProducesResponseType(typeof(Result), 200)] [ProducesResponseType(404)] - public IActionResult ChangeUserPasswordByHashCode([FromBody] ChangeUserPasswordByHashCodeVM changeUserPasswordByHashCodeVM) + public async Task ChangeUserPasswordByHashCodeAsync([FromBody] ChangeUserPasswordByHashCodeVM changeUserPasswordByHashCodeVM) { var result = _userService.ConfirmHashCodePassword(changeUserPasswordByHashCodeVM.HashCodePassword); if (!result.Success) return NotFound(result); var newPassword = changeUserPasswordByHashCodeVM.NewPassword; - var user = _userService.Find((result.Value as User).Id); + var user = await _userService.FindAsync((result.Value as User).Id); user.Password = newPassword; var resultChangePasswordUser = _userService.ChangeUserPassword(user, newPassword); @@ -267,10 +267,10 @@ private bool IsValidClientVersion(string client, string clientVersion) } } - private User GetSessionUser() + private async Task GetSessionUserAsync() { var userId = new Guid(Thread.CurrentPrincipal?.Identity?.Name); - return _userService.Find(userId); + return await _userService.FindAsync(userId); } } } \ No newline at end of file diff --git a/ShareBook/ShareBook.Api/Controllers/BookController.cs b/ShareBook/ShareBook.Api/Controllers/BookController.cs index a7e8f518..7b60d24a 100644 --- a/ShareBook/ShareBook.Api/Controllers/BookController.cs +++ b/ShareBook/ShareBook.Api/Controllers/BookController.cs @@ -96,19 +96,19 @@ public async Task ReceivedAsync(string bookId) [Authorize("Bearer")] [HttpPost("Cancel/{id}")] [ProducesResponseType(typeof(Result), 200)] - public IActionResult Cancel(string id, [FromQuery] string reason = "") + public async Task CancelAsync(string id, [FromQuery] string reason = "") { - if (!_IsBookOwner(new Guid(id))) return Unauthorized(); + if (!await _IsBookOwnerAsync(new Guid(id))) return Unauthorized(); var cancelationDTO = new BookCancelationDTO { - Book = _service.Find(new Guid(id)), - CanceledBy = GetSessionUser().Name, + Book = await _service.FindAsync(new Guid(id)), + CanceledBy = (await GetSessionUserAsync()).Name, Reason = reason }; - var returnBook = _bookUserService.Cancel(cancelationDTO).Value; - var returnBookVm = _mapper.Map(returnBook); + var returnBook = await _bookUserService.CancelAsync(cancelationDTO); + var returnBookVm = _mapper.Map(returnBook.Value); var result = new Result(returnBookVm); return Ok(result); } @@ -129,9 +129,9 @@ public IList FreightOptions() [Authorize("Bearer")] [HttpGet("RequestersList/{bookId}")] - public IActionResult GetRequestersList(Guid bookId) + public async Task GetRequestersListAsync(Guid bookId) { - if (!_IsBookOwner(bookId)) return Unauthorized(); + if (!await _IsBookOwnerAsync(bookId)) return Unauthorized(); var requesters = _bookUserService.GetRequestersList(bookId); var requestersVM = _mapper.Map>(requesters); @@ -141,9 +141,9 @@ public IActionResult GetRequestersList(Guid bookId) [HttpGet("Slug/{slug}")] [ProducesResponseType(typeof(BookVM), 200)] - public IActionResult Get(string slug) + public async Task GetAsync(string slug) { - var book = _service.BySlug(slug); + var book = await _service.BySlugAsync(slug); var bookVM = _mapper.Map(book); return book != null ? (IActionResult)Ok(bookVM) : NotFound(); } @@ -152,9 +152,9 @@ public IActionResult Get(string slug) [AuthorizationFilter(Permissions.Permission.ApproveBook)] // apenas adms [ProducesResponseType(typeof(BookVM), 200)] [HttpGet("{id}")] - public IActionResult GetById(string id) + public async Task GetByIdAsync(string id) { - var book = _service.Find(new Guid(id)); + var book = await _service.FindAsync(new Guid(id)); var bookVM = _mapper.Map(book); return bookVM != null ? (IActionResult)Ok(bookVM) : NotFound(); } @@ -181,9 +181,9 @@ public IList Random15EBooks() } [HttpGet("FullSearch/{criteria}/{page}/{items}")] - public PagedList FullSearch(string criteria, int page, int items) + public async Task> FullSearchAsync(string criteria, int page, int items) { - var books = _service.FullSearch(criteria, page, items); + var books = await _service.FullSearchAsync(criteria, page, items); var booksVM = _mapper.Map>(books.Items); return new PagedList() { @@ -197,16 +197,16 @@ public PagedList FullSearch(string criteria, int page, int items) [Authorize("Bearer")] [HttpGet("FullSearchAdmin/{criteria}")] [AuthorizationFilter(Permissions.Permission.DonateBook)] - public PagedList FullSearchAdmin(string criteria, int page, int items) + public async Task> FullSearchAdminAsync(string criteria, int page, int items) { var isAdmin = true; - return _service.FullSearch(criteria, page, items, isAdmin); + return await _service.FullSearchAsync(criteria, page, items, isAdmin); } [HttpGet("Category/{categoryId}/{page}/{items}")] - public PagedList ByCategoryId(Guid categoryId, int page, int items) + public async Task> ByCategoryIdAsync(Guid categoryId, int page, int items) { - var booksPaged = _service.ByCategoryId(categoryId, page, items); + var booksPaged = await _service.ByCategoryIdAsync(categoryId, page, items); var books = booksPaged.Items; var booksVM = _mapper.Map>(books); @@ -222,9 +222,9 @@ public PagedList ByCategoryId(Guid categoryId, int page, int items) [Authorize("Bearer")] [HttpPost("Request")] [ProducesResponseType(typeof(Result), 200)] - public IActionResult RequestBook([FromBody] RequestBookVM requestBookVM) + public async Task RequestBookAsync([FromBody] RequestBookVM requestBookVM) { - User user = GetUser(); + User user = await GetUserAsync(); if (_IsDonator(requestBookVM.BookId, user) && !_IsAdmin(user)) //Permitido solicitar o próprio livro somente para Admin throw new ShareBookException("Não é possivel solicitar esse livro pois você é o doador."); @@ -234,19 +234,19 @@ public IActionResult RequestBook([FromBody] RequestBookVM requestBookVM) [HttpPost("CancelRequest/{requestId}")] [Authorize("Bearer")] - public IActionResult CancelRequest(Guid requestId) + public async Task CancelRequestAsync(Guid requestId) { - var request = _bookUserService.GetRequest(requestId); + var request = await _bookUserService.GetRequestAsync(requestId); if (request == null) return NotFound(); - var user = GetUser(); + var user = await GetUserAsync(); if (request.UserId != user.Id) return Forbid(); - bool success = _bookUserService.CancelRequest(request); + bool success = await _bookUserService.CancelRequestAsync(request); if (!success) return BadRequest(); @@ -255,10 +255,10 @@ public IActionResult CancelRequest(Guid requestId) [HttpPost] [Authorize("Bearer")] - public IActionResult Create([FromBody] CreateBookVM createBookVM) + public async Task CreateAsync([FromBody] CreateBookVM createBookVM) { var book = _mapper.Map(createBookVM); - var result = _service.Insert(book); + var result = await _service.InsertAsync(book); if (!result.Success) { return BadRequest(result); @@ -269,11 +269,11 @@ public IActionResult Create([FromBody] CreateBookVM createBookVM) [HttpPut("{id}")] [Authorize("Bearer")] [AuthorizationFilter(Permissions.Permission.ApproveBook)] - public IActionResult Update(Guid Id, [FromBody] UpdateBookVM updateBookVM) + public async Task UpdateAsync(Guid Id, [FromBody] UpdateBookVM updateBookVM) { updateBookVM.Id = Id; var book = _mapper.Map(updateBookVM); - var result = _service.Update(book); + var result = await _service.UpdateAsync(book); if (!result.Success) { return BadRequest(result); @@ -286,7 +286,7 @@ public IActionResult Update(Guid Id, [FromBody] UpdateBookVM updateBookVM) [ProducesResponseType(typeof(Result), 200)] public async Task DonateBookAsync(Guid bookId, [FromBody] DonateBookUserVM donateBookUserVM) { - if (!_IsBookOwner(bookId)) return Unauthorized(); + if (!await _IsBookOwnerAsync(bookId)) return Unauthorized(); await _bookUserService.DonateBookAsync(bookId, donateBookUserVM.UserId, donateBookUserVM.Note); @@ -301,15 +301,15 @@ public async Task DonateBookAsync(Guid bookId, [FromBody] DonateB [Authorize("Bearer")] [HttpDelete("{id}")] [AuthorizationFilter(Permissions.Permission.DonateBook)] - public Result Delete(Guid id) => _service.Delete(id); + public async Task DeleteAsync(Guid id) => await _service.DeleteAsync(id); [Authorize("Bearer")] [HttpGet("Requested/{bookId}")] - public Result Requested(Guid bookId) + public async Task RequestedAsync(Guid bookId) { var result = new Result { - Value = new { bookRequested = _service.UserRequestedBook(bookId) }, + Value = new { bookRequested = await _service.UserRequestedBookAsync(bookId) }, }; return result; @@ -317,9 +317,9 @@ public Result Requested(Guid bookId) [Authorize("Bearer")] [HttpGet("MyRequests/{page}/{items}")] - public PagedList MyRequests(int page, int items) + public async Task> MyRequestsAsync(int page, int items) { - var donation = _bookUserService.GetRequestsByUser(page, items); + var donation = await _bookUserService.GetRequestsByUserAsync(page, items); var myBooksRequestsVM = _mapper.Map>(donation.Items); return new PagedList() @@ -333,19 +333,19 @@ public PagedList MyRequests(int page, int items) [Authorize("Bearer")] [HttpGet("MyDonations")] - public IList MyDonations() + public async Task> MyDonationsAsync() { Guid userId = new Guid(Thread.CurrentPrincipal?.Identity?.Name); - var donations = _service.GetUserDonations(userId); + var donations = await _service.GetUserDonationsAsync(userId); return _mapper.Map>(donations); } [Authorize("Bearer")] [ProducesResponseType(typeof(Result), 200)] [HttpPost("InformTrackingNumber/{bookId}")] - public IActionResult InformTrackingNumber(Guid bookId, [FromBody] TrackinNumberBookVM trackingNumberBookVM) + public async Task InformTrackingNumberAsync(Guid bookId, [FromBody] TrackinNumberBookVM trackingNumberBookVM) { - _bookUserService.InformTrackingNumber(bookId, trackingNumberBookVM.TrackingNumber); + await _bookUserService.InformTrackingNumberAsync(bookId, trackingNumberBookVM.TrackingNumber); return Ok(); } @@ -364,7 +364,7 @@ public IActionResult AddFacilitatorNotes([FromBody] AddFacilitatorNotesVM vm) [HttpGet("MainUsers/{bookId}")] public async Task MainUsers(Guid bookId) { - if (!_IsBookMainUser(bookId)) return Unauthorized(); + if (!await _IsBookMainUserAsync(bookId)) return Unauthorized(); var book = _service.GetBookWithAllUsers(bookId); @@ -380,7 +380,7 @@ public async Task MainUsers(Guid bookId) }; var userId = new Guid(Thread.CurrentPrincipal?.Identity?.Name); - var visitor = _userService.Find(userId); + var visitor = await _userService.FindAsync(userId); var visitorProfile = GetVisitorProfile(result); await _accessHistoryService.InsertVisitor(book.User, visitor, visitorProfile); @@ -419,9 +419,9 @@ VisitorProfile GetVisitorProfile(MainUsersVM mainUsers) [Authorize("Bearer")] [HttpPut("RenewChooseDate/{bookId}")] - public IActionResult RenewChooseDate(Guid bookId) + public async Task RenewChooseDateAsync(Guid bookId) { - if (!_IsBookOwner(bookId)) + if (!await _IsBookOwnerAsync(bookId)) return Unauthorized(); _service.RenewChooseDate(bookId); @@ -429,9 +429,9 @@ public IActionResult RenewChooseDate(Guid bookId) } // apenas doador e adm - private bool _IsBookOwner(Guid bookId) + private async Task _IsBookOwnerAsync(Guid bookId) { - User user = GetUser(); + User user = await GetUserAsync(); if (user == null) return false; @@ -451,10 +451,10 @@ private bool _IsDonator(Guid bookId, User user) return book.UserId == user.Id; } - private User GetUser() + private async Task GetUserAsync() { var userId = new Guid(Thread.CurrentPrincipal?.Identity?.Name); - return _userService.Find(userId); + return await _userService.FindAsync(userId); } private bool _IsAdmin(User user) @@ -464,9 +464,9 @@ private bool _IsAdmin(User user) } // doador, adm e ganhador - private bool _IsBookMainUser(Guid bookId) + private async Task _IsBookMainUserAsync(Guid bookId) { - if (_IsBookOwner(bookId)) + if (await _IsBookOwnerAsync(bookId)) return true; var userId = new Guid(Thread.CurrentPrincipal?.Identity?.Name); @@ -480,10 +480,10 @@ private bool _IsBookMainUser(Guid bookId) return false; } - private User GetSessionUser() + private async Task GetSessionUserAsync() { var userId = new Guid(Thread.CurrentPrincipal?.Identity?.Name); - return _userService.Find(userId); + return await _userService.FindAsync(userId); } } } \ No newline at end of file diff --git a/ShareBook/ShareBook.Api/Controllers/Generic/BaseCRUDController.cs b/ShareBook/ShareBook.Api/Controllers/Generic/BaseCRUDController.cs index bbf76656..42c2d651 100644 --- a/ShareBook/ShareBook.Api/Controllers/Generic/BaseCRUDController.cs +++ b/ShareBook/ShareBook.Api/Controllers/Generic/BaseCRUDController.cs @@ -7,6 +7,7 @@ using ShareBook.Domain.Common; using ShareBook.Service.Generic; using System; +using System.Threading.Tasks; namespace ShareBook.Api.Controllers { @@ -41,13 +42,13 @@ public BaseCrudController(IBaseService service, IMapper mapper) : base(servic [Authorize("Bearer")] [HttpPost] - public virtual Result Create([FromBody] R viewModel) + public virtual async Task> CreateAsync([FromBody] R viewModel) { if (!HasRequestViewModel) - return _mapper.Map>(_service.Insert(viewModel as T)); + return _mapper.Map>(await _service.InsertAsync(viewModel as T)); var entity = _mapper.Map(viewModel); - var result = _service.Insert(entity); + var result = await _service.InsertAsync(entity); var resultVM = _mapper.Map>(result); return resultVM; @@ -55,15 +56,15 @@ public virtual Result Create([FromBody] R viewModel) [Authorize("Bearer")] [HttpPut("{id}")] - public virtual Result Update(Guid id, [FromBody] R viewModel) + public virtual async Task> UpdateAsync(Guid id, [FromBody] R viewModel) { viewModel.Id = id; if (!HasRequestViewModel) - return _mapper.Map>(_service.Update(viewModel as T)); + return _mapper.Map>(await _service.UpdateAsync(viewModel as T)); var entity = _mapper.Map(viewModel); - var result = _service.Update(entity); + var result = await _service.UpdateAsync(entity); var resultVM = _mapper.Map(result); return new Result(resultVM); } diff --git a/ShareBook/ShareBook.Api/Controllers/Generic/BaseController.cs b/ShareBook/ShareBook.Api/Controllers/Generic/BaseController.cs index ea903564..e2459cfc 100644 --- a/ShareBook/ShareBook.Api/Controllers/Generic/BaseController.cs +++ b/ShareBook/ShareBook.Api/Controllers/Generic/BaseController.cs @@ -6,6 +6,7 @@ using ShareBook.Service.Generic; using System; using System.Linq.Expressions; +using System.Threading.Tasks; namespace ShareBook.Api.Controllers { @@ -54,6 +55,6 @@ protected void SetDefault(Expression> defaultOrder) public virtual PagedList Paged(int page, int items) => _service.Get(x => true, _defaultOrder, page, items); [HttpGet("{id}")] - public T GetById(string id) => _service.Find(new Guid(id)); + public async Task GetByIdAsync(string id) => await _service.FindAsync(new Guid(id)); } } \ No newline at end of file diff --git a/ShareBook/ShareBook.Api/Controllers/Generic/BaseDeleteController.cs b/ShareBook/ShareBook.Api/Controllers/Generic/BaseDeleteController.cs index bb64f12f..073cc154 100644 --- a/ShareBook/ShareBook.Api/Controllers/Generic/BaseDeleteController.cs +++ b/ShareBook/ShareBook.Api/Controllers/Generic/BaseDeleteController.cs @@ -6,6 +6,7 @@ using ShareBook.Domain.Common; using ShareBook.Service.Generic; using System; +using System.Threading.Tasks; namespace ShareBook.Api.Controllers { @@ -34,6 +35,6 @@ public BaseDeleteController(IBaseService service) : base(service) { } [Authorize("Bearer")] [HttpDelete("{id}")] - public Result Delete(Guid id) => _service.Delete(id); + public async Task Delete(Guid id) => await _service.DeleteAsync(id); } } diff --git a/ShareBook/ShareBook.Service/Book/BookService.cs b/ShareBook/ShareBook.Service/Book/BookService.cs index ce1c2794..827f5a9a 100644 --- a/ShareBook/ShareBook.Service/Book/BookService.cs +++ b/ShareBook/ShareBook.Service/Book/BookService.cs @@ -165,15 +165,15 @@ public IList GetAll(int page, int items) .Skip((page - 1) * items) .Take(items).ToList(); - public override Book Find(object keyValue) + public override async Task FindAsync(object keyValue) { - var result = _repository.Get() + var result = await _repository.Get() .Include(b => b.User) .ThenInclude(u => u.Address) .Include(b => b.Category) .Include(b => b.UserFacilitator) .Where(b => b.Id == (Guid)keyValue) - .FirstOrDefault(); + .FirstOrDefaultAsync(); if (result == null) throw new ShareBookException(ShareBookException.Error.NotFound); @@ -183,14 +183,13 @@ public override Book Find(object keyValue) return result; } - public override Result Insert(Book entity) + public override async Task> InsertAsync(Book entity) { - // TODO: Migrate to Async and remove ".GetAwaiter().GetResult()" and ".Wait()" entity.UserId = new Guid(Thread.CurrentPrincipal?.Identity?.Name); EBookValidate(entity); - var result = Validate(entity); + var result = await ValidateAsync(entity); if (result.Success) { entity.Slug = SetSlugByTitleOrIncremental(entity); @@ -198,22 +197,21 @@ public override Result Insert(Book entity) entity.ImageSlug = ImageHelper.FormatImageName(entity.ImageName, entity.Slug); if (entity.IsEbookPdfValid()) - entity.EBookPdfFile = _uploadService.UploadPdfAsync(entity.EBookPdfBytes, entity.EBookPdfFile, "EBooks").GetAwaiter().GetResult(); + entity.EBookPdfFile = await _uploadService.UploadPdfAsync(entity.EBookPdfBytes, entity.EBookPdfFile, "EBooks"); - result.Value = _repository.Insert(entity); + result.Value = await _repository.InsertAsync(entity); - result.Value.ImageUrl = _uploadService.UploadImageAsync(entity.ImageBytes, entity.ImageSlug, "Books").GetAwaiter().GetResult(); + result.Value.ImageUrl = await _uploadService.UploadImageAsync(entity.ImageBytes, entity.ImageSlug, "Books"); result.Value.ImageBytes = null; - _booksEmailService.SendEmailNewBookInsertedAsync(entity).Wait(); + await _booksEmailService.SendEmailNewBookInsertedAsync(entity); } return result; } - public override Result Update(Book entity) + public override async Task> UpdateAsync(Book entity) { - // TODO: Migrate to Async and remove ".GetAwaiter().GetResult()" and ".Wait()" Result result = Validate(entity, x => x.Title, x => x.Author, @@ -225,7 +223,7 @@ public override Result Update(Book entity) if (!result.Success) return result; //buscar o book no banco para obter um objeto para ser re-hidratado - var savedBook = this._repository.Find(bookId); + var savedBook = await this._repository.FindAsync(bookId); if (savedBook == null) throw new ShareBookException(ShareBookException.Error.NotFound); @@ -236,7 +234,7 @@ public override Result Update(Book entity) if (!string.IsNullOrEmpty(entity.ImageName) && entity.ImageBytes.Length > 0) { entity.ImageSlug = ImageHelper.FormatImageName(entity.ImageName, savedBook.Slug); - _uploadService.UploadImageAsync(entity.ImageBytes, savedBook.ImageSlug, "Books").GetAwaiter().GetResult(); + await _uploadService.UploadImageAsync(entity.ImageBytes, savedBook.ImageSlug, "Books"); } //preparar o book para atualização @@ -258,14 +256,13 @@ public override Result Update(Book entity) if (entity.UserIdFacilitator.HasValue && entity.UserIdFacilitator != Guid.Empty) savedBook.UserIdFacilitator = entity.UserIdFacilitator; - // TODO: Remove "GetAwaiter().GetResult()" - result.Value = _repository.UpdateAsync(savedBook).GetAwaiter().GetResult(); + result.Value = await _repository.UpdateAsync(savedBook); result.Value.ImageBytes = null; return result; } - public PagedList FullSearch(string criteria, int page, int itemsPerPage, bool isAdmin) + public async Task> FullSearchAsync(string criteria, int page, int itemsPerPage, bool isAdmin) { Expression> filter = x => (x.Author.Contains(criteria) || x.Title.Contains(criteria) @@ -276,22 +273,22 @@ public PagedList FullSearch(string criteria, int page, int itemsPerPage, b || x.Title.Contains(criteria) || x.Category.Name.Contains(criteria); - return SearchBooks(filter, page, itemsPerPage); + return await SearchBooksAsync(filter, page, itemsPerPage); } - public PagedList ByCategoryId(Guid categoryId, int page, int itemsPerPage) - => SearchBooks(x => x.Status == BookStatus.Available && x.CategoryId == categoryId, page, itemsPerPage); + public async Task> ByCategoryIdAsync(Guid categoryId, int page, int itemsPerPage) + => await SearchBooksAsync(x => x.Status == BookStatus.Available && x.CategoryId == categoryId, page, itemsPerPage); - public Book BySlug(string slug) + public async Task BySlugAsync(string slug) { - var pagedBook = SearchBooks(x => (x.Slug.Equals(slug)), 1, 1); + var pagedBook = await SearchBooksAsync(x => (x.Slug.Equals(slug)), 1, 1); return pagedBook.Items.FirstOrDefault(); } - public bool UserRequestedBook(Guid bookId) + public async Task UserRequestedBookAsync(Guid bookId) { var userId = new Guid(Thread.CurrentPrincipal?.Identity?.Name); - return _repository.Any(x => + return await _repository.AnyAsync(x => x.Id == bookId && x.BookUsers .Any(y => @@ -303,13 +300,13 @@ public bool UserRequestedBook(Guid bookId) public override PagedList Get(Expression> filter, Expression> order, int page, int itemsPerPage) => base.Get(filter, order, page, itemsPerPage); - public IList GetUserDonations(Guid userId) + public async Task> GetUserDonationsAsync(Guid userId) { - return _repository.Get() + return await _repository.Get() .Include(b => b.BookUsers) .Where(b => b.UserId == userId) .OrderByDescending(b => b.CreationDate) - .ToList(); + .ToListAsync(); } public async Task> GetBooksChooseDateIsTodayAsync() @@ -377,6 +374,7 @@ public void AddFacilitatorNotes(Guid bookId, string facilitatorNotes) public Book GetBookWithAllUsers(Guid bookId) { + // TODO: Migrate to async/await var books = _repository .Get().Include(x => x.User).ThenInclude(u => u.Address) .Include(x => x.UserFacilitator).ThenInclude(u => u.Address) @@ -389,6 +387,7 @@ public Book GetBookWithAllUsers(Guid bookId) public void RenewChooseDate(Guid bookId) { + // TODO: Migrate to async/await var book = _repository.Find(bookId); if (book == null) throw new ShareBookException(ShareBookException.Error.NotFound); @@ -403,10 +402,10 @@ public void RenewChooseDate(Guid bookId) #region Private - private PagedList SearchBooks(Expression> filter, int page, int itemsPerPage) - => SearchBooks(filter, page, itemsPerPage, x => x.CreationDate); + private async Task> SearchBooksAsync(Expression> filter, int page, int itemsPerPage) + => await SearchBooksAsync(filter, page, itemsPerPage, x => x.CreationDate); - private PagedList SearchBooks(Expression> filter, int page, int itemsPerPage, Expression> expression) + private async Task> SearchBooksAsync(Expression> filter, int page, int itemsPerPage, Expression> expression) { var query = _repository.Get() .Where(filter) @@ -443,7 +442,7 @@ private PagedList SearchBooks(Expression> filter, i Category = u.Category }); - return FormatPagedList(query, page, itemsPerPage); + return await FormatPagedListAsync(query, page, itemsPerPage); } private string SetSlugByTitleOrIncremental(Book entity) @@ -451,7 +450,7 @@ private string SetSlugByTitleOrIncremental(Book entity) var slug = _repository.Get() .Where(x => x.Title.ToUpper().Trim().Equals(entity.Title.ToUpper().Trim()) && !x.Id.Equals(entity.Id)) - .OrderByDescending(x => x.CreationDate)?.FirstOrDefault()?.Slug; + .OrderByDescending(x => x.CreationDate).FirstOrDefault()?.Slug; return string.IsNullOrWhiteSpace(slug) ? entity.Title.GenerateSlug() : slug.AddIncremental(); } @@ -467,16 +466,16 @@ private void EBookValidate(Book entity) } } - public BookStatsDTO GetStats() + public async Task GetStatsAsync() { - var groupedStatus = _repository.Get() + var groupedStatus = await _repository.Get() .GroupBy(b => b.Status) .Select(g => new { Status = g.Key, Total = g.Count() }) - .ToList(); + .ToListAsync(); var status = new BookStatsDTO(); diff --git a/ShareBook/ShareBook.Service/Book/BooksEmailService.cs b/ShareBook/ShareBook.Service/Book/BooksEmailService.cs index 0c6a3f34..690726a0 100644 --- a/ShareBook/ShareBook.Service/Book/BooksEmailService.cs +++ b/ShareBook/ShareBook.Service/Book/BooksEmailService.cs @@ -39,7 +39,7 @@ public BooksEmailService( public async Task SendEmailBookApprovedAsync(Book book) { if (book.User == null) - book.User = _userService.Find(book.UserId); + book.User = await _userService.FindAsync(book.UserId); if (book.User.AllowSendingEmail) { @@ -57,7 +57,7 @@ public async Task SendEmailBookApprovedAsync(Book book) public async Task SendEmailBookReceivedAsync(Book book) { if (book.User == null) - book.User = _userService.Find(book.UserId); + book.User = await _userService.FindAsync(book.UserId); if (book.User.AllowSendingEmail) { @@ -76,7 +76,7 @@ public async Task SendEmailBookReceivedAsync(Book book) public async Task SendEmailNewBookInsertedAsync(Book book) { if (book.User == null) - book.User = _userService.Find(book.UserId); + book.User = await _userService.FindAsync(book.UserId); var userStats = _userService.GetStats(book.UserId); diff --git a/ShareBook/ShareBook.Service/Book/IBookService.cs b/ShareBook/ShareBook.Service/Book/IBookService.cs index df61057e..8b9168ab 100644 --- a/ShareBook/ShareBook.Service/Book/IBookService.cs +++ b/ShareBook/ShareBook.Service/Book/IBookService.cs @@ -24,17 +24,17 @@ public interface IBookService : IBaseService IList Random15EBooks(); - PagedList FullSearch(string criteria, int page, int itemsPerPage, bool isAdmin = false); + Task> FullSearchAsync(string criteria, int page, int itemsPerPage, bool isAdmin = false); - PagedList ByCategoryId(Guid categoryId, int page, int items); + Task> ByCategoryIdAsync(Guid categoryId, int page, int items); IList GetAll(int page, int items); - Book BySlug(string slug); + Task BySlugAsync(string slug); - bool UserRequestedBook(Guid bookId); + Task UserRequestedBookAsync(Guid bookId); - IList GetUserDonations(Guid userId); + Task> GetUserDonationsAsync(Guid userId); Task> GetBooksChooseDateIsTodayAsync(); @@ -47,6 +47,6 @@ public interface IBookService : IBaseService Book GetBookWithAllUsers(Guid bookId); void RenewChooseDate(Guid bookId); - BookStatsDTO GetStats(); + Task GetStatsAsync(); } } diff --git a/ShareBook/ShareBook.Service/BookUser/BookUserEmailService.cs b/ShareBook/ShareBook.Service/BookUser/BookUserEmailService.cs index 38b290f1..0721cecb 100644 --- a/ShareBook/ShareBook.Service/BookUser/BookUserEmailService.cs +++ b/ShareBook/ShareBook.Service/BookUser/BookUserEmailService.cs @@ -46,7 +46,7 @@ public async Task SendEmailBookDonated(BookUser bookUser) { var bookDonated = bookUser.Book; if (bookDonated.User == null) - bookDonated.User = _userService.Find(bookUser.Book.UserId); + bookDonated.User = await _userService.FindAsync(bookUser.Book.UserId); if (bookDonated.User.AllowSendingEmail) { @@ -85,7 +85,7 @@ public async Task SendEmailBookDonor(BookUser bookUser, Book bookRequested) return; //obter o endereço do interessado - var donatedUser = this._userService.Find(bookUser.UserId); + var donatedUser = await this._userService.FindAsync(bookUser.UserId); if (bookRequested.User.AllowSendingEmail) { var htmlTable = GenerateInterestedListHtml(bookRequested); @@ -157,7 +157,7 @@ public async Task SendEmailBookInterested(BookUser bookUser, Book book) { // lazy load depression if (bookUser.User == null) - bookUser.User = _userService.Find(bookUser.UserId); + bookUser.User = await _userService.FindAsync(bookUser.UserId); if (bookUser.User.AllowSendingEmail) { diff --git a/ShareBook/ShareBook.Service/BookUser/BookUserService.cs b/ShareBook/ShareBook.Service/BookUser/BookUserService.cs index 374af0c7..ea9b1a6e 100644 --- a/ShareBook/ShareBook.Service/BookUser/BookUserService.cs +++ b/ShareBook/ShareBook.Service/BookUser/BookUserService.cs @@ -106,7 +106,7 @@ private void MaxRequestsValidation(Book bookRequested) public async Task DonateBookAsync(Guid bookId, Guid userId, string note) { - var book = _bookService.Find(bookId); + var book = await _bookService.FindAsync(bookId); if (!book.MayChooseWinner()) throw new ShareBookException(ShareBookException.Error.BadRequest, "Aguarde a data de decisão."); @@ -129,7 +129,7 @@ public async Task DonateBookAsync(Guid bookId, Guid userId, string note) await _bookUserRepository.UpdateAsync(bookUserAccepted); - DeniedBookUsers(bookId); + await DeniedBookUsersAsync(bookId); await _bookService.UpdateBookStatusAsync(bookId, BookStatus.WaitingSend); @@ -146,44 +146,44 @@ public async Task DonateBookAsync(Guid bookId, Guid userId, string note) await _bookUsersEmailService.SendEmailBookDonatedNotifyDonor(bookUserAccepted.Book, bookUserAccepted.User); } - public Result Cancel(BookCancelationDTO dto) + public async Task> CancelAsync(BookCancelationDTO dto) { if (dto.Book == null) throw new ShareBookException(ShareBookException.Error.NotFound); - // TODO: Migrate to "ToListAsync" - var bookUsers = _bookUserRepository.Get().Where(x => x.BookId == dto.Book.Id).ToList(); + // TODO: Verify if we can remove this call + var bookUsers = await _bookUserRepository.Get().Where(x => x.BookId == dto.Book.Id).ToListAsync(); dto.Book.ChooseDate = null; dto.Book.Status = BookStatus.Canceled; - CancelBookUsersAndSendNotification(dto.Book); + await CancelBookUsersAndSendNotificationAsync(dto.Book); - _bookService.Update(dto.Book); - _bookUsersEmailService.SendEmailBookCanceledToAdminsAndDonor(dto).Wait(); + await _bookService.UpdateAsync(dto.Book); + await _bookUsersEmailService.SendEmailBookCanceledToAdminsAndDonor(dto); return new Result(dto.Book); } - public void DeniedBookUsers(Guid bookId) + public async Task DeniedBookUsersAsync(Guid bookId) { - var bookUsersDenied = _bookUserRepository.Get().Where(x => x.BookId == bookId - && x.Status == DonationStatus.WaitingAction).ToList(); + var bookUsersDenied = await _bookUserRepository.Get().Where(x => x.BookId == bookId + && x.Status == DonationStatus.WaitingAction).ToListAsync(); foreach (var item in bookUsersDenied) { string note = string.Empty; item.UpdateBookUser(DonationStatus.Denied, note); - _bookUserRepository.Update(item); + await _bookUserRepository.UpdateAsync(item); } } - private void CancelBookUsersAndSendNotification(Book book) + private async Task CancelBookUsersAndSendNotificationAsync(Book book) { - DeniedBookUsers(book.Id); - NotifyUsersBookCanceled(book); + await DeniedBookUsersAsync(book.Id); + await NotifyUsersBookCanceledAsync(book); } - public PagedList GetRequestsByUser(int page, int itemsPerPage) + public async Task> GetRequestsByUserAsync(int page, int itemsPerPage) { var userId = new Guid(Thread.CurrentPrincipal?.Identity?.Name); var query = _bookUserRepository.Get() @@ -191,7 +191,7 @@ public PagedList GetRequestsByUser(int page, int itemsPerPage) .Where(x => x.UserId == userId) .OrderByDescending(x => x.CreationDate); - var result = FormatPagedList(query, page, itemsPerPage); + var result = await FormatPagedListAsync(query, page, itemsPerPage); // só mostra o código de rastreio se ele for o ganhador. result.Items = result.Items.Select(bu => @@ -206,13 +206,13 @@ public PagedList GetRequestsByUser(int page, int itemsPerPage) public async Task NotifyInterestedAboutBooksWinner(Guid bookId) { //Obter todos os users do livro - var bookUsers = _bookUserRepository.Get() + var bookUsers = await _bookUserRepository.Get() .Include(u => u.Book) .Include(u => u.User) - .Where(x => x.BookId == bookId).ToList(); + .Where(x => x.BookId == bookId).ToListAsync(); //obter apenas o ganhador - var winnerBookUser = bookUsers.Where(bu => bu.Status == DonationStatus.Donated).FirstOrDefault(); + var winnerBookUser = bookUsers.FirstOrDefault(bu => bu.Status == DonationStatus.Donated); //Book var book = winnerBookUser.Book; @@ -222,71 +222,65 @@ public async Task NotifyInterestedAboutBooksWinner(Guid bookId) //enviar e-mails await this._bookUsersEmailService.SendEmailDonationDeclined(book, winnerBookUser, losersBookUser); - } - public void NotifyUsersBookCanceled(Book book) + public async Task NotifyUsersBookCanceledAsync(Book book) { - - - List bookUsers = _bookUserRepository.Get() + List bookUsers = await _bookUserRepository.Get() .Include(u => u.User) - .Where(x => x.BookId == book.Id).ToList(); - - - this._bookUsersEmailService.SendEmailDonationCanceled(book, bookUsers).Wait(); + .Where(x => x.BookId == book.Id).ToListAsync(); + await this._bookUsersEmailService.SendEmailDonationCanceled(book, bookUsers); } - public void InformTrackingNumber(Guid bookId, string trackingNumber) + public async Task InformTrackingNumberAsync(Guid bookId, string trackingNumber) { - var book = _bookRepository.Get() + var book = await _bookRepository.Get() .Include(d => d.User) .Include(f => f.UserFacilitator) - .FirstOrDefault(id => id.Id == bookId); - var winnerBookUser = _bookUserRepository + .FirstOrDefaultAsync(id => id.Id == bookId); + var winnerBookUser = await _bookUserRepository .Get() .Include(u => u.User) .Where(bu => bu.BookId == bookId && bu.Status == DonationStatus.Donated) - .FirstOrDefault(); + .FirstOrDefaultAsync(); if (winnerBookUser == null) throw new ShareBookException("Vencedor ainda não foi escolhido"); if (MuambatorConfigurator.IsActive) - _muambatorService.AddPackageToTrackerAsync(book, winnerBookUser.User, trackingNumber); + await _muambatorService.AddPackageToTrackerAsync(book, winnerBookUser.User, trackingNumber); book.Status = BookStatus.Sent; book.TrackingNumber = trackingNumber; - _bookService.Update(book); + await _bookService.UpdateAsync(book); if (winnerBookUser.User.AllowSendingEmail) //Envia e-mail para avisar o ganhador do tracking number - _bookUsersEmailService.SendEmailTrackingNumberInformed(winnerBookUser, book).Wait(); + await _bookUsersEmailService.SendEmailTrackingNumberInformed(winnerBookUser, book); } + /// /// Cancel a request for a book if it's still awaiting for donor decision and not already canceled. /// /// The request to be canceled /// Returns true if the operation gets executed successfully - public bool CancelRequest(BookUser request) + public async Task CancelRequestAsync(BookUser request) { if (request.Book.Status == BookStatus.AwaitingDonorDecision || request.Book.Status == BookStatus.Available && request.Status != DonationStatus.Canceled) { request.UpdateBookUser(DonationStatus.Canceled, String.Empty); request.Reason = "Pedido cancelado! Favor ignorar."; - _bookUserRepository.Update(request); + await _bookUserRepository.UpdateAsync(request); return true; } return false; } - public BookUser GetRequest(Guid requestId) + public async Task GetRequestAsync(Guid requestId) { - return _bookUserRepository.Find(new IncludeList(x => x.Book), x => x.Id == requestId); + return await _bookUserRepository.FindAsync(new IncludeList(x => x.Book), x => x.Id == requestId); } - - } } diff --git a/ShareBook/ShareBook.Service/BookUser/IBookUserService.cs b/ShareBook/ShareBook.Service/BookUser/IBookUserService.cs index a10156fa..263604b8 100644 --- a/ShareBook/ShareBook.Service/BookUser/IBookUserService.cs +++ b/ShareBook/ShareBook.Service/BookUser/IBookUserService.cs @@ -17,9 +17,9 @@ public interface IBookUserService Task DonateBookAsync(Guid bookId, Guid userId, string note); - void DeniedBookUsers(Guid bookId); + Task DeniedBookUsersAsync(Guid bookId); - PagedList GetRequestsByUser(int page, int items); + Task> GetRequestsByUserAsync(int page, int items); /// /// Comunicar os interessados não escolhidos sobre a finalização da doação. e quem ganhou o livro @@ -27,10 +27,10 @@ public interface IBookUserService /// Task NotifyInterestedAboutBooksWinner(Guid bookId); - Result Cancel(BookCancelationDTO dto); + Task> CancelAsync(BookCancelationDTO dto); - void InformTrackingNumber(Guid bookId, string trackingNumber); - BookUser GetRequest(Guid requestId); - bool CancelRequest(BookUser request); + Task InformTrackingNumberAsync(Guid bookId, string trackingNumber); + Task GetRequestAsync(Guid requestId); + Task CancelRequestAsync(BookUser request); } } diff --git a/ShareBook/ShareBook.Service/Generic/BaseService.cs b/ShareBook/ShareBook.Service/Generic/BaseService.cs index 422614d8..b8de287a 100644 --- a/ShareBook/ShareBook.Service/Generic/BaseService.cs +++ b/ShareBook/ShareBook.Service/Generic/BaseService.cs @@ -1,4 +1,5 @@ using FluentValidation; +using Microsoft.EntityFrameworkCore; using ShareBook.Domain.Common; using ShareBook.Repository; using ShareBook.Repository.Repository; @@ -6,6 +7,7 @@ using System; using System.Linq; using System.Linq.Expressions; +using System.Threading.Tasks; namespace ShareBook.Service.Generic { @@ -26,18 +28,18 @@ public BaseService(IRepositoryGeneric repository, IUnitOfWork unitOfWor public bool Any(Expression> filter) => _repository.Any(filter); - public int Count(Expression> filter) => _repository.Count(filter); + public async Task CountAsync(Expression> filter) => await _repository.CountAsync(filter); - public virtual TEntity Find(object keyValue) - => _repository.Find(keyValue); + public virtual async Task FindAsync(object keyValue) + => await _repository.FindAsync(keyValue); - public virtual TEntity Find(IncludeList includes, object keyValue) - => _repository.Find(includes, keyValue); + public virtual async Task FindAsync(IncludeList includes, object keyValue) + => await _repository.FindAsync(includes, keyValue); public TEntity Find(Expression> filter) => _repository.Find(filter); - public TEntity Find(IncludeList includes, Expression> filter) => _repository.Find(includes, filter); + public async Task FindAsync(IncludeList includes, Expression> filter) => await _repository.FindAsync(includes, filter); public PagedList Get(Expression> order) => _repository.Get(order); @@ -63,48 +65,48 @@ public virtual PagedList Get(Expression> filt public PagedList Get(Expression> filter, Expression> order, int page, int itemsPerPage, IncludeList includes) => _repository.Get(filter, order, page, itemsPerPage, includes); - public PagedList FormatPagedList(IQueryable query, int page, int itemsPerPage) + public async Task> FormatPagedListAsync(IQueryable query, int page, int itemsPerPage) { - var total = query.Count(); + var total = await query.CountAsync(); var skip = (page - 1) * itemsPerPage; return new PagedList() { Page = page, ItemsPerPage = itemsPerPage, TotalItems = total, - Items = query.Skip(skip).Take(itemsPerPage).ToList() + Items = await query.Skip(skip).Take(itemsPerPage).ToListAsync() }; } #endregion GET - protected Result Validate(TEntity entity) => new Result(_validator.Validate(entity)); + protected async Task> ValidateAsync(TEntity entity) => new Result(await _validator.ValidateAsync(entity)); protected Result Validate(TEntity entity, params Expression>[] filter) => new Result(_validator.Validate(entity, filter)); - public virtual Result Insert(TEntity entity) + public virtual async Task> InsertAsync(TEntity entity) { - var result = Validate(entity); + var result = await ValidateAsync(entity); if (result.Success) - result.Value = _repository.Insert(entity); + result.Value = await _repository.InsertAsync(entity); return result; } - public virtual Result Update(TEntity entity) + public virtual async Task> UpdateAsync(TEntity entity) { - var result = Validate(entity); + var result = await ValidateAsync(entity); if (result.Success) - result.Value = _repository.Update(entity); + result.Value = await _repository.UpdateAsync(entity); return result; } - public Result Delete(params object[] keyValues) + public async Task DeleteAsync(params object[] keyValues) { - _repository.Delete(keyValues); + await _repository.DeleteAsync(keyValues); return new Result(); } } diff --git a/ShareBook/ShareBook.Service/Generic/IBaseService.cs b/ShareBook/ShareBook.Service/Generic/IBaseService.cs index a433d552..2cdae10c 100644 --- a/ShareBook/ShareBook.Service/Generic/IBaseService.cs +++ b/ShareBook/ShareBook.Service/Generic/IBaseService.cs @@ -2,25 +2,26 @@ using ShareBook.Repository.Repository; using System; using System.Linq.Expressions; +using System.Threading.Tasks; namespace ShareBook.Service.Generic { public interface IBaseService where TEntity : class { bool Any(Expression> filter); - int Count(Expression> filter); + Task CountAsync(Expression> filter); /// /// Execute a Find on the DbSet using the . /// Using this method will return onlye the Entity, without the children. /// If you want to get the Child Objects too, use the method. /// - TEntity Find(object keyValue); + Task FindAsync(object keyValue); /// /// Execute a Find on the DbSet using the and the /// - TEntity Find(IncludeList includes, object keyValue); + Task FindAsync(IncludeList includes, object keyValue); /// /// Find in the DbSet an entity that matches the specified filter. @@ -35,7 +36,7 @@ public interface IBaseService where TEntity : class /// Includes (child objects) to be returned. /// Entity with the child objects /// In case that more than 1 entity could be returned for the filter specified. - TEntity Find(IncludeList includes, Expression> filter); + Task FindAsync(IncludeList includes, Expression> filter); /// /// Get ALL the entities, without filter, on the specified order, without child objects. @@ -89,8 +90,8 @@ public interface IBaseService where TEntity : class /// First Page = 1 PagedList Get(Expression> filter, Expression> order, int page, int itemsPerPage, IncludeList includes); - Result Insert(TEntity entity); - Result Update(TEntity entity); - Result Delete(params object[] keyValues); + Task> InsertAsync(TEntity entity); + Task> UpdateAsync(TEntity entity); + Task DeleteAsync(params object[] keyValues); } } diff --git a/ShareBook/ShareBook.Service/Lgpd/ILgpdService.cs b/ShareBook/ShareBook.Service/Lgpd/ILgpdService.cs index 67a4df08..df8a0932 100644 --- a/ShareBook/ShareBook.Service/Lgpd/ILgpdService.cs +++ b/ShareBook/ShareBook.Service/Lgpd/ILgpdService.cs @@ -1,9 +1,10 @@ using ShareBook.Domain.DTOs; +using System.Threading.Tasks; namespace ShareBook.Service.Lgpd { public interface ILgpdService { - public void Anonymize(UserAnonymizeDTO dto); + public Task AnonymizeAsync(UserAnonymizeDTO dto); } } diff --git a/ShareBook/ShareBook.Service/Lgpd/LgpdService.cs b/ShareBook/ShareBook.Service/Lgpd/LgpdService.cs index 73e4c471..78433589 100644 --- a/ShareBook/ShareBook.Service/Lgpd/LgpdService.cs +++ b/ShareBook/ShareBook.Service/Lgpd/LgpdService.cs @@ -5,6 +5,7 @@ using ShareBook.Domain.Exceptions; using ShareBook.Repository; using System.Linq; +using System.Threading.Tasks; namespace ShareBook.Service.Lgpd { @@ -27,14 +28,14 @@ public LgpdService( _ctx = context; } - public void Anonymize(UserAnonymizeDTO dto) + public async Task AnonymizeAsync(UserAnonymizeDTO dto) { - var user = _ctx.Users + var user = await _ctx.Users .Where(u => u.Id == dto.UserId) .Include(u => u.Address) .Include(u => u.BooksDonated) .Include(u => u.BookUsers) // livros solicitados - .FirstOrDefault(); + .FirstOrDefaultAsync(); if (user == null) throw new ShareBookException(ShareBookException.Error.NotFound, "Nenhum usuário encontrado."); @@ -52,7 +53,7 @@ public void Anonymize(UserAnonymizeDTO dto) RemoveOpenRequests(user); // 2 - Cancela doações em aberto. - RemoveOpenDonations(user); + await RemoveOpenDonationsAsync(user); // 3 - Anonimiza a conta user.Anonymize(); @@ -64,7 +65,7 @@ public void Anonymize(UserAnonymizeDTO dto) _userEmailService.SendEmailAnonymizeNotifyAdms(dto); // 6 - Enfim salva - _ctx.SaveChanges(); + await _ctx.SaveChangesAsync(); } @@ -79,18 +80,18 @@ private void RemoveOpenRequests(User user) } } - private void RemoveOpenDonations(User user) + private async Task RemoveOpenDonationsAsync(User user) { foreach (var book in user.BooksDonated) { if (book.Status == BookStatus.WaitingApproval || book.Status == BookStatus.Available || book.Status == BookStatus.AwaitingDonorDecision) { - CancelDonation(book); + await CancelDonationAsync(book); } } } - private void CancelDonation(Book book) + private async Task CancelDonationAsync(Book book) { var cancelationDTO = new BookCancelationDTO { @@ -99,7 +100,7 @@ private void CancelDonation(Book book) Reason = "Doação cancelada porque o usuário removeu a própria conta." }; - _bookUserService.Cancel(cancelationDTO); + await _bookUserService.CancelAsync(cancelationDTO); } private void RemoveLogs(User user) diff --git a/ShareBook/ShareBook.Service/User/IUserService.cs b/ShareBook/ShareBook.Service/User/IUserService.cs index d6a054b6..6f6c0c1f 100644 --- a/ShareBook/ShareBook.Service/User/IUserService.cs +++ b/ShareBook/ShareBook.Service/User/IUserService.cs @@ -4,6 +4,7 @@ using ShareBook.Service.Generic; using System; using System.Collections.Generic; +using System.Threading.Tasks; namespace ShareBook.Service { @@ -11,7 +12,7 @@ public interface IUserService : IBaseService { Result AuthenticationByEmailAndPassword(User user); bool IsValidPassword(User user, string decryptedPass); - new Result Update(User user); + Task> UpdateAsync(User user); Result ValidOldPasswordAndChangeUserPassword(User user, string newPassword); Result ChangeUserPassword(User user, string newPassword); Result GenerateHashCodePasswordAndSendEmailToUser(string email); diff --git a/ShareBook/ShareBook.Service/User/UserService.cs b/ShareBook/ShareBook.Service/User/UserService.cs index d5166c07..400cf6f9 100644 --- a/ShareBook/ShareBook.Service/User/UserService.cs +++ b/ShareBook/ShareBook.Service/User/UserService.cs @@ -2,9 +2,9 @@ using System.Collections.Generic; using System.Linq; using System.Threading; +using System.Threading.Tasks; using AutoMapper; using FluentValidation; -using Microsoft.EntityFrameworkCore; using ShareBook.Domain; using ShareBook.Domain.Common; using ShareBook.Domain.DTOs; @@ -68,6 +68,7 @@ public Result AuthenticationByEmailAndPassword(User user) // persiste última tentativa de login ANTES do SUCESSO ou FALHA pra ter métrica de // verificação de brute force. user.LastLogin = DateTime.Now; + // TODO: Migrate to Async _userRepository.Update(user); if (!IsValidPassword(user, decryptedPass)) @@ -133,7 +134,7 @@ private void ParentAprovalStartFlow(RegisterUserDTO userDto, User user) _userEmailService.SendEmailRequestParentAproval(userDto, user); } - public override Result Update(User user) + public override async Task> UpdateAsync(User user) { user.Id = new Guid(Thread.CurrentPrincipal?.Identity?.Name); Result result = Validate(user, x => @@ -145,11 +146,11 @@ public override Result Update(User user) if (!result.Success) return result; - var userAux = _repository.Find(new IncludeList(x => x.Address), user.Id); + var userAux = await _repository.FindAsync(new IncludeList(x => x.Address), user.Id); if (userAux == null) result.Messages.Add("Usuário não existe."); - if (_repository.Any(u => u.Email == user.Email && u.Id != user.Id)) + if (await _repository.AnyAsync(u => u.Email == user.Email && u.Id != user.Id)) result.Messages.Add("Email já existe."); if (result.Success) @@ -157,16 +158,16 @@ public override Result Update(User user) userAux.Change(user.Email, user.Name, user.Linkedin, user.Instagram, user.Phone, user.AllowSendingEmail); userAux.ChangeAddress(user.Address); - result.Value = UserCleanup(_repository.Update(userAux)); + result.Value = UserCleanup(await _repository.UpdateAsync(userAux)); } return result; } - public override User Find(object keyValue) + public override async Task FindAsync(object keyValue) { var includes = new IncludeList(x => x.Address); - return _repository.Find(includes, keyValue); + return await _repository.FindAsync(includes, keyValue); } public Result ValidOldPasswordAndChangeUserPassword(User user, string newPassword) @@ -198,6 +199,7 @@ public Result ChangeUserPassword(User user, string newPassword) public Result GenerateHashCodePasswordAndSendEmailToUser(string email) { + // TODO: Migrate to async/await var result = new Result(); var user = _repository.Find(e => e.Email == email); diff --git a/ShareBook/ShareBook.Test.Unit/Services/BookServiceTests.cs b/ShareBook/ShareBook.Test.Unit/Services/BookServiceTests.cs index a2866606..9b25753c 100644 --- a/ShareBook/ShareBook.Test.Unit/Services/BookServiceTests.cs +++ b/ShareBook/ShareBook.Test.Unit/Services/BookServiceTests.cs @@ -8,13 +8,12 @@ using ShareBook.Repository.UoW; using ShareBook.Service; using ShareBook.Service.AwsSqs; -using ShareBook.Service.AwsSqs.Dto; -using ShareBook.Service.Muambator; using ShareBook.Service.Upload; using ShareBook.Test.Unit.Mocks; using System; using System.Text; using System.Threading; +using System.Threading.Tasks; using Xunit; namespace ShareBook.Test.Unit.Services @@ -43,22 +42,22 @@ public BookServiceTests() configurationMock = new Mock(); sqsMock = new Mock(); - bookRepositoryMock.Setup(repo => repo.Insert(It.IsAny())).Returns(() => + bookRepositoryMock.Setup(repo => repo.InsertAsync(It.IsAny())).ReturnsAsync(() => { return BookMock.GetLordTheRings(); }); - uploadServiceMock.Setup(service => service.UploadImageAsync(null, null, null)); - bookServiceMock.Setup(service => service.Insert(It.IsAny())).Verifiable(); + uploadServiceMock.Setup(service => service.UploadImageAsync(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync("Ok Mocked"); + bookServiceMock.Setup(service => service.InsertAsync(It.IsAny())).ReturnsAsync(() => new Result(new Book())).Verifiable(); } [Fact] - public void AddBook() + public async Task AddBook() { Thread.CurrentPrincipal = new UserMock().GetClaimsUser(); var service = new BookService(bookRepositoryMock.Object, unitOfWorkMock.Object, new BookValidator(), uploadServiceMock.Object, bookEmailService.Object, configurationMock.Object, sqsMock.Object); - Result result = service.Insert(new Book() + Result result = await service.InsertAsync(new Book() { Title = "Lord of the Rings", Author = "J. R. R. Tolkien", @@ -73,13 +72,13 @@ public void AddBook() } [Fact] - public void AddEBookByLink() + public async Task AddEBookByLink() { Thread.CurrentPrincipal = new UserMock().GetClaimsUser(); var service = new BookService(bookRepositoryMock.Object, unitOfWorkMock.Object, new BookValidator(), uploadServiceMock.Object, bookEmailService.Object, configurationMock.Object, sqsMock.Object); - Result result = service.Insert(new Book() + Result result = await service.InsertAsync(new Book() { Title = "Lord of the Rings", Author = "J. R. R. Tolkien", @@ -95,13 +94,13 @@ public void AddEBookByLink() } [Fact] - public void AddEBookByPdfFile() + public async Task AddEBookByPdfFile() { Thread.CurrentPrincipal = new UserMock().GetClaimsUser(); var service = new BookService(bookRepositoryMock.Object, unitOfWorkMock.Object, new BookValidator(), uploadServiceMock.Object, bookEmailService.Object, configurationMock.Object, sqsMock.Object); - Result result = service.Insert(new Book() + Result result = await service.InsertAsync(new Book() { Title = "Lord of the Rings", Author = "J. R. R. Tolkien", diff --git a/ShareBook/ShareBook.Test.Unit/Services/UserServiceTests.cs b/ShareBook/ShareBook.Test.Unit/Services/UserServiceTests.cs index 55e5134a..4179432a 100644 --- a/ShareBook/ShareBook.Test.Unit/Services/UserServiceTests.cs +++ b/ShareBook/ShareBook.Test.Unit/Services/UserServiceTests.cs @@ -15,7 +15,8 @@ using ShareBook.Repository.UoW; using ShareBook.Infra.CrossCutting.Identity.Interfaces; using AutoMapper; -using ShareBook.Service.Recaptcha; +using ShareBook.Service.Recaptcha; +using System.Threading.Tasks; namespace ShareBook.Test.Unit.Services { @@ -50,7 +51,7 @@ public UserServiceTests() return UserMock.GetGrantee(); }); - userRepositoryMock.Setup(repo => repo.Update(It.IsAny())).Returns(() => + userRepositoryMock.Setup(repo => repo.UpdateAsync(It.IsAny())).ReturnsAsync(() => { return UserMock.GetGrantee(); }); @@ -60,7 +61,7 @@ public UserServiceTests() return UserMock.GetGrantee(); }); - userRepositoryMock.Setup(repo => repo.Find(It.IsAny>(), It.IsAny())).Returns(() => + userRepositoryMock.Setup(repo => repo.FindAsync(It.IsAny>(), It.IsAny())).ReturnsAsync(() => { return UserMock.GetGrantee(); }); @@ -74,16 +75,17 @@ public UserServiceTests() }.AsQueryable(); }); - userServiceMock.Setup(service => service.Insert(It.IsAny())).Verifiable(); + userServiceMock.Setup(service => service.InsertAsync(It.IsAny())).Verifiable(); + userServiceMock.Setup(service => service.UpdateAsync(It.IsAny())).Verifiable(); } #region Register User [Fact] - public void RegisterValidUser() + public async Task RegisterValidUser() { var service = new UserService(userRepositoryMock.Object, bookRepositoryMock.Object, unitOfWorkMock.Object, new UserValidator(), mapperMock.Object, userEmailServiceMock.Object, recaptchaServiceMock.Object); - Result result = service.Insert(new User() + Result result = await service.InsertAsync(new User() { Email = "jose@sharebook.com", Password = "Password.123", @@ -97,11 +99,11 @@ public void RegisterValidUser() } [Fact] - public void RegisterInvalidUser() + public async Task RegisterInvalidUser() { var service = new UserService(userRepositoryMock.Object, bookRepositoryMock.Object, unitOfWorkMock.Object, new UserValidator(), mapperMock.Object, userEmailServiceMock.Object, recaptchaServiceMock.Object); - Result result = service.Insert(new User() + Result result = await service.InsertAsync(new User() { Email = "", Password = "" @@ -114,11 +116,11 @@ public void RegisterInvalidUser() #region Update User [Fact] - public void UpdateValidUser() + public async Task UpdateValidUser() { var service = new UserService(userRepositoryMock.Object, bookRepositoryMock.Object, unitOfWorkMock.Object, new UserValidator(), mapperMock.Object, userEmailServiceMock.Object, recaptchaServiceMock.Object); - Result result = service.Update(new User() + Result result = await service.UpdateAsync(new User() { Id = new Guid("C53B3552-606C-40C6-9D7F-FFC87572977E"), Email = "sergioprates.student@gmail.com", @@ -142,11 +144,11 @@ public void UpdateValidUser() } [Fact] - public void UpdateInvalidUser() + public async Task UpdateInvalidUser() { var service = new UserService(userRepositoryMock.Object, bookRepositoryMock.Object, unitOfWorkMock.Object, new UserValidator(), mapperMock.Object, userEmailServiceMock.Object, recaptchaServiceMock.Object); - Result result = service.Update(new User() + Result result = await service.UpdateAsync(new User() { Email = "", Linkedin = "", @@ -159,11 +161,11 @@ public void UpdateInvalidUser() } [Fact] - public void UpdateUserNotExists() + public async Task UpdateUserNotExists() { var service = new UserService(userRepositoryMock.Object, bookRepositoryMock.Object, unitOfWorkMock.Object, new UserValidator(), mapperMock.Object, userEmailServiceMock.Object, recaptchaServiceMock.Object); - Result result = service.Update(new User() + Result result = await service.UpdateAsync(new User() { Email = "sss@sss.com", Linkedin = "" diff --git a/ShareBook/Sharebook.Jobs/Jobs/0 - CancelAbandonedDonations.cs b/ShareBook/Sharebook.Jobs/Jobs/0 - CancelAbandonedDonations.cs index 10c3a7d2..4a285a6f 100644 --- a/ShareBook/Sharebook.Jobs/Jobs/0 - CancelAbandonedDonations.cs +++ b/ShareBook/Sharebook.Jobs/Jobs/0 - CancelAbandonedDonations.cs @@ -50,8 +50,7 @@ public override async Task WorkAsync() Reason = $"Cancelamento automático de doação abandonada. Com mais de {_maxLateDonationDaysAutoCancel} dias de atraso.", }; - // TODO: Migrate to async - _bookUserService.Cancel(dto); + await _bookUserService.CancelAsync(dto); details += $"Doação do livro {book.Title} foi cancelada.\n"; } diff --git a/ShareBook/Sharebook.Jobs/Jobs/2 - LateDonationNotification.cs b/ShareBook/Sharebook.Jobs/Jobs/2 - LateDonationNotification.cs index 9706b546..2b501978 100644 --- a/ShareBook/Sharebook.Jobs/Jobs/2 - LateDonationNotification.cs +++ b/ShareBook/Sharebook.Jobs/Jobs/2 - LateDonationNotification.cs @@ -44,7 +44,7 @@ public LateDonationNotification(IJobHistoryRepository jobHistoryRepo, public override async Task WorkAsync() { - var status = _bookService.GetStats(); + var status = await _bookService.GetStatsAsync(); var booksLate = await _bookService.GetBooksChooseDateIsLateAsync(); var donators = GetDistinctDonators(booksLate); diff --git a/ShareBook/Sharebook.Jobs/Jobs/3 - RemoveBookFromShowcase.cs b/ShareBook/Sharebook.Jobs/Jobs/3 - RemoveBookFromShowcase.cs index e1ded63c..eaebcf19 100644 --- a/ShareBook/Sharebook.Jobs/Jobs/3 - RemoveBookFromShowcase.cs +++ b/ShareBook/Sharebook.Jobs/Jobs/3 - RemoveBookFromShowcase.cs @@ -66,8 +66,7 @@ public override async Task WorkAsync() await SendEmailAsync(book); } - // TODO: Migrate to async - _bookService.Update(book); + await _bookService.UpdateAsync(book); } return new JobHistory() diff --git a/ShareBook/Sharebook.Jobs/Jobs/5 - NewBookGetInterestedUsers.cs b/ShareBook/Sharebook.Jobs/Jobs/5 - NewBookGetInterestedUsers.cs index 97484556..da325dad 100644 --- a/ShareBook/Sharebook.Jobs/Jobs/5 - NewBookGetInterestedUsers.cs +++ b/ShareBook/Sharebook.Jobs/Jobs/5 - NewBookGetInterestedUsers.cs @@ -117,7 +117,7 @@ private int GetEmailMaxDestinationsPerQueueMessage() } private async Task GetEmailTemplateAsync(Guid bookId){ - var book = _bookService.Find(bookId); + var book = await _bookService.FindAsync(bookId); var vm = new { From a584a9937ef70b82a0168d48315f666b0317dffd Mon Sep 17 00:00:00 2001 From: Henrique Holtz Date: Wed, 12 Jun 2024 08:08:49 -0300 Subject: [PATCH 03/37] chore: IRepositoryGeneric => Remove sync methods without any usage --- .../Repository/Generic/IRepositoryGeneric.cs | 14 -------------- .../Repository/Generic/RepositoryGeneric.cs | 8 +------- 2 files changed, 1 insertion(+), 21 deletions(-) diff --git a/ShareBook/ShareBook.Repository/Repository/Generic/IRepositoryGeneric.cs b/ShareBook/ShareBook.Repository/Repository/Generic/IRepositoryGeneric.cs index 96d75a75..54e0b6bb 100644 --- a/ShareBook/ShareBook.Repository/Repository/Generic/IRepositoryGeneric.cs +++ b/ShareBook/ShareBook.Repository/Repository/Generic/IRepositoryGeneric.cs @@ -130,16 +130,6 @@ public interface IRepositoryGeneric where TEntity : class /// First Page = 1 PagedList Get(Expression> filter, Expression> order, int page, int itemsPerPage, IncludeList includes); - /// - /// Execute the count based on the specified filter. - /// - /// Don't use it to verify if there is any entity that satisfy the condition. To do it, use - /// the method. - /// - /// - /// The number of entities that satisfy the filter - int Count(Expression> filter); - /// /// Verify if there is any entity that satisfy the specified filter. /// @@ -150,10 +140,6 @@ public interface IRepositoryGeneric where TEntity : class TEntity Update(TEntity entity); - void Delete(params object[] keyValues); - - void Delete(TEntity entity); - IQueryable FromSql(string query, object[] parameters); } } \ No newline at end of file diff --git a/ShareBook/ShareBook.Repository/Repository/Generic/RepositoryGeneric.cs b/ShareBook/ShareBook.Repository/Repository/Generic/RepositoryGeneric.cs index 212c9854..a6901278 100644 --- a/ShareBook/ShareBook.Repository/Repository/Generic/RepositoryGeneric.cs +++ b/ShareBook/ShareBook.Repository/Repository/Generic/RepositoryGeneric.cs @@ -53,7 +53,7 @@ public async Task FindAsync(IncludeList includes, Expression 1) throw new ShareBookException("More than one entity find for the specified filter"); - return query.FirstOrDefault(); + return await query.FirstOrDefaultAsync(); } public virtual async Task> GetAsync( @@ -193,18 +193,12 @@ public PagedList Get(Expression> filter, Expr public PagedList Get(Expression> filter, Expression> order, int page, int itemsPerPage, IncludeList includes) => GetAsync(filter, order, page, itemsPerPage, includes).GetAwaiter().GetResult(); - public int Count(Expression> filter) => CountAsync(filter).GetAwaiter().GetResult(); - public bool Any(Expression> filter) => AnyAsync(filter).GetAwaiter().GetResult(); public TEntity Insert(TEntity entity) => InsertAsync(entity).GetAwaiter().GetResult(); public TEntity Update(TEntity entity) => UpdateAsync(entity).GetAwaiter().GetResult(); - public void Delete(params object[] keyValues) => DeleteAsync(keyValues).GetAwaiter().GetResult(); - - public void Delete(TEntity entity) => DeleteAsync(entity).GetAwaiter().GetResult(); - #endregion Synchronous } } \ No newline at end of file From 1ccb4c1e8e2fdbdf188811bcc5b193e8cce649a5 Mon Sep 17 00:00:00 2001 From: Henrique Holtz Date: Wed, 12 Jun 2024 08:10:09 -0300 Subject: [PATCH 04/37] perf: IUserService => Turning method "GenerateHashCodePasswordAndSendEmailToUser" as async --- ShareBook/ShareBook.Api/Controllers/AccountController.cs | 4 ++-- ShareBook/ShareBook.Service/User/IUserService.cs | 2 +- ShareBook/ShareBook.Service/User/UserService.cs | 7 +++---- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/ShareBook/ShareBook.Api/Controllers/AccountController.cs b/ShareBook/ShareBook.Api/Controllers/AccountController.cs index 05e66e1e..b264a16d 100644 --- a/ShareBook/ShareBook.Api/Controllers/AccountController.cs +++ b/ShareBook/ShareBook.Api/Controllers/AccountController.cs @@ -160,9 +160,9 @@ public IActionResult Login( [HttpPost("ForgotMyPassword")] [ProducesResponseType(typeof(Result), 200)] [ProducesResponseType(404)] - public IActionResult ForgotMyPassword([FromBody] ForgotMyPasswordVM forgotMyPasswordVM) + public async Task ForgotMyPasswordAsync([FromBody] ForgotMyPasswordVM forgotMyPasswordVM) { - var result = _userService.GenerateHashCodePasswordAndSendEmailToUser(forgotMyPasswordVM.Email); + var result = await _userService.GenerateHashCodePasswordAndSendEmailToUserAsync(forgotMyPasswordVM.Email); if (result.Success) return Ok(result); diff --git a/ShareBook/ShareBook.Service/User/IUserService.cs b/ShareBook/ShareBook.Service/User/IUserService.cs index 6f6c0c1f..66027b69 100644 --- a/ShareBook/ShareBook.Service/User/IUserService.cs +++ b/ShareBook/ShareBook.Service/User/IUserService.cs @@ -15,7 +15,7 @@ public interface IUserService : IBaseService Task> UpdateAsync(User user); Result ValidOldPasswordAndChangeUserPassword(User user, string newPassword); Result ChangeUserPassword(User user, string newPassword); - Result GenerateHashCodePasswordAndSendEmailToUser(string email); + Task GenerateHashCodePasswordAndSendEmailToUserAsync(string email); Result ConfirmHashCodePassword(string hashCodePassword); IList GetFacilitators(Guid userIdDonator); IList GetAdmins(); diff --git a/ShareBook/ShareBook.Service/User/UserService.cs b/ShareBook/ShareBook.Service/User/UserService.cs index 400cf6f9..c8806bef 100644 --- a/ShareBook/ShareBook.Service/User/UserService.cs +++ b/ShareBook/ShareBook.Service/User/UserService.cs @@ -197,9 +197,8 @@ public Result ChangeUserPassword(User user, string newPassword) return result; } - public Result GenerateHashCodePasswordAndSendEmailToUser(string email) + public async Task GenerateHashCodePasswordAndSendEmailToUserAsync(string email) { - // TODO: Migrate to async/await var result = new Result(); var user = _repository.Find(e => e.Email == email); @@ -210,8 +209,8 @@ public Result GenerateHashCodePasswordAndSendEmailToUser(string email) } user.GenerateHashCodePassword(); - _repository.Update(user); - _userEmailService.SendEmailForgotMyPasswordToUserAsync(user).Wait(); + await _repository.UpdateAsync(user); + await _userEmailService.SendEmailForgotMyPasswordToUserAsync(user); result.SuccessMessage = "E-mail enviado com as instruções para recuperação da senha."; return result; } From b2eccd58f7c84ccc2f6c98f71ccb23ace5948c7e Mon Sep 17 00:00:00 2001 From: Henrique Holtz Date: Wed, 12 Jun 2024 08:11:15 -0300 Subject: [PATCH 05/37] chore: IUserService.UpdateAsync => Adding new keyword to get rid the warning --- ShareBook/ShareBook.Service/User/IUserService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ShareBook/ShareBook.Service/User/IUserService.cs b/ShareBook/ShareBook.Service/User/IUserService.cs index 66027b69..836e91b4 100644 --- a/ShareBook/ShareBook.Service/User/IUserService.cs +++ b/ShareBook/ShareBook.Service/User/IUserService.cs @@ -12,7 +12,7 @@ public interface IUserService : IBaseService { Result AuthenticationByEmailAndPassword(User user); bool IsValidPassword(User user, string decryptedPass); - Task> UpdateAsync(User user); + new Task> UpdateAsync(User user); Result ValidOldPasswordAndChangeUserPassword(User user, string newPassword); Result ChangeUserPassword(User user, string newPassword); Task GenerateHashCodePasswordAndSendEmailToUserAsync(string email); From 19907e3c7f86527e6817d73bc3279d618a180cfa Mon Sep 17 00:00:00 2001 From: Henrique Holtz Date: Wed, 12 Jun 2024 08:26:33 -0300 Subject: [PATCH 06/37] perf: Turning some methods as async in IBookService, IBookUserService, IUserService --- .../Controllers/BookController.cs | 20 ++++---- .../ShareBook.Service/Book/BookService.cs | 46 +++++++++---------- .../ShareBook.Service/Book/IBookService.cs | 8 ++-- .../BookUser/BookUserService.cs | 12 ++--- .../BookUser/IBookUserService.cs | 2 +- .../ShareBook.Service/User/IUserService.cs | 2 +- .../ShareBook.Service/User/UserService.cs | 5 +- .../Services/BookUserServiceTests.cs | 8 ++-- .../Jobs/3 - RemoveBookFromShowcase.cs | 3 +- .../Jobs/5 - NewBookGetInterestedUsers.cs | 3 +- 10 files changed, 55 insertions(+), 54 deletions(-) diff --git a/ShareBook/ShareBook.Api/Controllers/BookController.cs b/ShareBook/ShareBook.Api/Controllers/BookController.cs index 7b60d24a..7f8d83a9 100644 --- a/ShareBook/ShareBook.Api/Controllers/BookController.cs +++ b/ShareBook/ShareBook.Api/Controllers/BookController.cs @@ -225,10 +225,10 @@ public async Task> ByCategoryIdAsync(Guid categoryId, int page public async Task RequestBookAsync([FromBody] RequestBookVM requestBookVM) { User user = await GetUserAsync(); - if (_IsDonator(requestBookVM.BookId, user) && !_IsAdmin(user)) //Permitido solicitar o próprio livro somente para Admin + if (await _IsDonatorAsync(requestBookVM.BookId, user) && !_IsAdmin(user)) //Permitido solicitar o próprio livro somente para Admin throw new ShareBookException("Não é possivel solicitar esse livro pois você é o doador."); - _bookUserService.Insert(requestBookVM.BookId, requestBookVM.Reason); + await _bookUserService.InsertAsync(requestBookVM.BookId, requestBookVM.Reason); return Ok(new Result { SuccessMessage = "Pedido realizado com sucesso!" }); } @@ -353,9 +353,9 @@ public async Task InformTrackingNumberAsync(Guid bookId, [FromBod [ProducesResponseType(typeof(Result), 200)] [HttpPost("AddFacilitatorNotes")] [AuthorizationFilter(Permissions.Permission.ApproveBook)] - public IActionResult AddFacilitatorNotes([FromBody] AddFacilitatorNotesVM vm) + public async Task AddFacilitatorNotesAsync([FromBody] AddFacilitatorNotesVM vm) { - _service.AddFacilitatorNotes(vm.BookId, vm.FacilitatorNotes); + await _service.AddFacilitatorNotesAsync(vm.BookId, vm.FacilitatorNotes); return Ok(); } @@ -366,7 +366,7 @@ public async Task MainUsers(Guid bookId) { if (!await _IsBookMainUserAsync(bookId)) return Unauthorized(); - var book = _service.GetBookWithAllUsers(bookId); + var book = await _service.GetBookWithAllUsersAsync(bookId); var donor = _mapper.Map(book.User); var facilitator = _mapper.Map(book.UserFacilitator); @@ -424,7 +424,7 @@ public async Task RenewChooseDateAsync(Guid bookId) if (!await _IsBookOwnerAsync(bookId)) return Unauthorized(); - _service.RenewChooseDate(bookId); + await _service.RenewChooseDateAsync(bookId); return Ok(); } @@ -439,13 +439,13 @@ private async Task _IsBookOwnerAsync(Guid bookId) if (_IsAdmin(user)) return true; // Doador - return _IsDonator(bookId, user); + return await _IsDonatorAsync(bookId, user); } - private bool _IsDonator(Guid bookId, User user) + private async Task _IsDonatorAsync(Guid bookId, User user) { if (user == null || user.Id == Guid.Empty) return false; - Book book = _service.GetBookWithAllUsers(bookId); + Book book = await _service.GetBookWithAllUsersAsync(bookId); if (book == null || book.Id == Guid.Empty) return false; return book.UserId == user.Id; @@ -470,7 +470,7 @@ private async Task _IsBookMainUserAsync(Guid bookId) return true; var userId = new Guid(Thread.CurrentPrincipal?.Identity?.Name); - var book = _service.GetBookWithAllUsers(bookId); + var book = await _service.GetBookWithAllUsersAsync(bookId); // Ganhador var winner = book.WinnerUser(); diff --git a/ShareBook/ShareBook.Service/Book/BookService.cs b/ShareBook/ShareBook.Service/Book/BookService.cs index 827f5a9a..c60d65f5 100644 --- a/ShareBook/ShareBook.Service/Book/BookService.cs +++ b/ShareBook/ShareBook.Service/Book/BookService.cs @@ -343,24 +343,24 @@ public async Task> GetBooksChooseDateIsLateAsync() /// Bom para remover o livro da vitrine. /// /// - public IList GetBooksChooseDateIsTodayOrLate() + public async Task> GetBooksChooseDateIsTodayOrLateAsync() { // limite é o dia de hoje. DateTime endDateTime = DateTime.Today.AddDays(1).AddTicks(-1); //Today at 23:59:59 // livros em que o choosedate é hoje. - var books = _repository - .Get().Include(x => x.User).Include(x => x.BookUsers).Include(x => x.UserFacilitator) - .Where(x => - x.ChooseDate <= endDateTime && x.Status == BookStatus.Available - ).ToList(); + var books = await _repository + .Get().Include(x => x.User).Include(x => x.BookUsers).Include(x => x.UserFacilitator) + .Where(x => + x.ChooseDate <= endDateTime && x.Status == BookStatus.Available + ).ToListAsync(); return books; } - public void AddFacilitatorNotes(Guid bookId, string facilitatorNotes) + public async Task AddFacilitatorNotesAsync(Guid bookId, string facilitatorNotes) { - var book = _repository.Find(bookId); + var book = await _repository.FindAsync(bookId); if (book == null) throw new ShareBookException(ShareBookException.Error.NotFound); @@ -369,26 +369,25 @@ public void AddFacilitatorNotes(Guid bookId, string facilitatorNotes) var lineBreak = (string.IsNullOrEmpty(book.FacilitatorNotes)) ? "" : "\n"; book.FacilitatorNotes += string.Format("{0}{1} - {2}", lineBreak, date, facilitatorNotes); - _repository.Update(book); + await _repository.UpdateAsync(book); } - public Book GetBookWithAllUsers(Guid bookId) + public async Task GetBookWithAllUsersAsync(Guid bookId) { - // TODO: Migrate to async/await - var books = _repository - .Get().Include(x => x.User).ThenInclude(u => u.Address) - .Include(x => x.UserFacilitator).ThenInclude(u => u.Address) - .Include(x => x.BookUsers).ThenInclude(bu => bu.User).ThenInclude(u => u.Address) - .Where(x => x.Id == bookId) - .ToList(); + // TODO: Verify if we can use FirstOrDefault/FirstOrDefaultAsync directly without using the "ToListAsync" + var books = await _repository + .Get().Include(x => x.User).ThenInclude(u => u.Address) + .Include(x => x.UserFacilitator).ThenInclude(u => u.Address) + .Include(x => x.BookUsers).ThenInclude(bu => bu.User).ThenInclude(u => u.Address) + .Where(x => x.Id == bookId) + .ToListAsync(); return books.FirstOrDefault(); } - public void RenewChooseDate(Guid bookId) + public async Task RenewChooseDateAsync(Guid bookId) { - // TODO: Migrate to async/await - var book = _repository.Find(bookId); + var book = await _repository.FindAsync(bookId); if (book == null) throw new ShareBookException(ShareBookException.Error.NotFound); @@ -397,7 +396,7 @@ public void RenewChooseDate(Guid bookId) book.Status = BookStatus.Available; book.ChooseDate = DateTime.Now.AddDays(10); - _repository.Update(book); + await _repository.UpdateAsync(book); } #region Private @@ -447,6 +446,7 @@ private async Task> SearchBooksAsync(Expression x.Title.ToUpper().Trim().Equals(entity.Title.ToUpper().Trim()) && !x.Id.Equals(entity.Id)) @@ -479,8 +479,8 @@ public async Task GetStatsAsync() var status = new BookStatsDTO(); - status.TotalWaitingApproval = groupedStatus.Where(g => g.Status == BookStatus.WaitingApproval).Any() - ? groupedStatus.Where(g => g.Status == BookStatus.WaitingApproval).FirstOrDefault().Total + status.TotalWaitingApproval = groupedStatus.Exists(g => g.Status == BookStatus.WaitingApproval) + ? groupedStatus.Find(g => g.Status == BookStatus.WaitingApproval).Total : 0; status.TotalOk = groupedStatus diff --git a/ShareBook/ShareBook.Service/Book/IBookService.cs b/ShareBook/ShareBook.Service/Book/IBookService.cs index 8b9168ab..13551432 100644 --- a/ShareBook/ShareBook.Service/Book/IBookService.cs +++ b/ShareBook/ShareBook.Service/Book/IBookService.cs @@ -40,13 +40,13 @@ public interface IBookService : IBaseService Task> GetBooksChooseDateIsLateAsync(); - IList GetBooksChooseDateIsTodayOrLate(); + Task> GetBooksChooseDateIsTodayOrLateAsync(); - void AddFacilitatorNotes(Guid bookId, string facilitatorNotes); + Task AddFacilitatorNotesAsync(Guid bookId, string facilitatorNotes); - Book GetBookWithAllUsers(Guid bookId); + Task GetBookWithAllUsersAsync(Guid bookId); - void RenewChooseDate(Guid bookId); + Task RenewChooseDateAsync(Guid bookId); Task GetStatsAsync(); } } diff --git a/ShareBook/ShareBook.Service/BookUser/BookUserService.cs b/ShareBook/ShareBook.Service/BookUser/BookUserService.cs index ea9b1a6e..fa435ddf 100644 --- a/ShareBook/ShareBook.Service/BookUser/BookUserService.cs +++ b/ShareBook/ShareBook.Service/BookUser/BookUserService.cs @@ -60,10 +60,10 @@ public IList GetRequestersList(Guid bookId) => .OrderBy(x => x.CreationDate) .ToList(); - public void Insert(Guid bookId, string reason) + public async Task InsertAsync(Guid bookId, string reason) { //obtem o livro requisitado e o doador - var bookRequested = _bookService.GetBookWithAllUsers(bookId); + var bookRequested = await _bookService.GetBookWithAllUsersAsync(bookId); var bookUser = new BookUser() { BookId = bookId, @@ -75,19 +75,19 @@ public void Insert(Guid bookId, string reason) if (!_bookService.Any(x => x.Id == bookUser.BookId)) throw new ShareBookException(ShareBookException.Error.NotFound); - if (_bookUserRepository.Any(x => x.UserId == bookUser.UserId && x.BookId == bookUser.BookId)) + if (await _bookUserRepository.AnyAsync(x => x.UserId == bookUser.UserId && x.BookId == bookUser.BookId)) throw new ShareBookException("O usuário já possui uma requisição para o mesmo livro."); if (bookRequested.Status != BookStatus.Available) throw new ShareBookException("Esse livro não está mais disponível para doação."); - _bookUserRepository.Insert(bookUser); + await _bookUserRepository.InsertAsync(bookUser); // Remove da vitrine caso o número de pedidos estiver grande demais. MaxRequestsValidation(bookRequested); - _bookUsersEmailService.SendEmailBookDonor(bookUser, bookRequested).Wait(); - _bookUsersEmailService.SendEmailBookInterested(bookUser, bookRequested).Wait(); + await _bookUsersEmailService.SendEmailBookDonor(bookUser, bookRequested); + await _bookUsersEmailService.SendEmailBookInterested(bookUser, bookRequested); } diff --git a/ShareBook/ShareBook.Service/BookUser/IBookUserService.cs b/ShareBook/ShareBook.Service/BookUser/IBookUserService.cs index 263604b8..306487d2 100644 --- a/ShareBook/ShareBook.Service/BookUser/IBookUserService.cs +++ b/ShareBook/ShareBook.Service/BookUser/IBookUserService.cs @@ -9,7 +9,7 @@ namespace ShareBook.Service { public interface IBookUserService { - void Insert(Guid bookId, string reason); + Task InsertAsync(Guid bookId, string reason); IList GetGranteeUsersByBookId(Guid bookId); diff --git a/ShareBook/ShareBook.Service/User/IUserService.cs b/ShareBook/ShareBook.Service/User/IUserService.cs index 836e91b4..caea50dc 100644 --- a/ShareBook/ShareBook.Service/User/IUserService.cs +++ b/ShareBook/ShareBook.Service/User/IUserService.cs @@ -19,7 +19,7 @@ public interface IUserService : IBaseService Result ConfirmHashCodePassword(string hashCodePassword); IList GetFacilitators(Guid userIdDonator); IList GetAdmins(); - IList GetBySolicitedBookCategory(Guid BookCategoryId); + Task> GetBySolicitedBookCategoryAsync(Guid BookCategoryId); UserStatsDTO GetStats(Guid? userId); Result Insert(RegisterUserDTO userDto); void ParentAproval(string parentHashCodeAproval); diff --git a/ShareBook/ShareBook.Service/User/UserService.cs b/ShareBook/ShareBook.Service/User/UserService.cs index c8806bef..b3188b22 100644 --- a/ShareBook/ShareBook.Service/User/UserService.cs +++ b/ShareBook/ShareBook.Service/User/UserService.cs @@ -5,6 +5,7 @@ using System.Threading.Tasks; using AutoMapper; using FluentValidation; +using Microsoft.EntityFrameworkCore; using ShareBook.Domain; using ShareBook.Domain.Common; using ShareBook.Domain.DTOs; @@ -306,8 +307,8 @@ private User UserCleanup(User user) return user; } - public IList GetBySolicitedBookCategory(Guid bookCategoryId) => - _userRepository.Get().Where(u => u.AllowSendingEmail && u.BookUsers.Any(bu => bu.Book.CategoryId == bookCategoryId)).ToList(); + public async Task> GetBySolicitedBookCategoryAsync(Guid bookCategoryId) => + await _userRepository.Get().Where(u => u.AllowSendingEmail && u.BookUsers.Any(bu => bu.Book.CategoryId == bookCategoryId)).ToListAsync(); public UserStatsDTO GetStats(Guid? userId) { diff --git a/ShareBook/ShareBook.Test.Unit/Services/BookUserServiceTests.cs b/ShareBook/ShareBook.Test.Unit/Services/BookUserServiceTests.cs index 860f0c80..63c06c5e 100644 --- a/ShareBook/ShareBook.Test.Unit/Services/BookUserServiceTests.cs +++ b/ShareBook/ShareBook.Test.Unit/Services/BookUserServiceTests.cs @@ -8,6 +8,7 @@ using ShareBook.Test.Unit.Mocks; using System; using System.Threading; +using System.Threading.Tasks; using Xunit; namespace ShareBook.Test.Unit.Services @@ -43,14 +44,14 @@ public BookUserServiceTests() bookServiceMock.SetReturnsDefault(true); - bookServiceMock.Setup(s => s.GetBookWithAllUsers(It.IsAny())).Returns(() => + bookServiceMock.Setup(s => s.GetBookWithAllUsersAsync(It.IsAny())).ReturnsAsync(() => { return BookMock.GetLordTheRings(); }); } [Fact] - public void RequestBook() + public async Task RequestBook() { Thread.CurrentPrincipal = new UserMock().GetClaimsUser(); var service = new BookUserService(bookUserRepositoryMock.Object, @@ -60,8 +61,9 @@ public void RequestBook() string reason = "I need this book because I'm learning a new programming language."; - service.Insert(bookId, reason); + await service.InsertAsync(bookId, reason); + // TODO: Verify test and add at least one assertion } } } diff --git a/ShareBook/Sharebook.Jobs/Jobs/3 - RemoveBookFromShowcase.cs b/ShareBook/Sharebook.Jobs/Jobs/3 - RemoveBookFromShowcase.cs index eaebcf19..9cfd6aca 100644 --- a/ShareBook/Sharebook.Jobs/Jobs/3 - RemoveBookFromShowcase.cs +++ b/ShareBook/Sharebook.Jobs/Jobs/3 - RemoveBookFromShowcase.cs @@ -38,8 +38,7 @@ public override async Task WorkAsync() { var messages = new List(); - // TODO: Migrate to async - var books = _bookService.GetBooksChooseDateIsTodayOrLate(); + var books = await _bookService.GetBooksChooseDateIsTodayOrLateAsync(); if (books.Count == 0) messages.Add("Nenhum livro encontrado."); diff --git a/ShareBook/Sharebook.Jobs/Jobs/5 - NewBookGetInterestedUsers.cs b/ShareBook/Sharebook.Jobs/Jobs/5 - NewBookGetInterestedUsers.cs index da325dad..799c18a5 100644 --- a/ShareBook/Sharebook.Jobs/Jobs/5 - NewBookGetInterestedUsers.cs +++ b/ShareBook/Sharebook.Jobs/Jobs/5 - NewBookGetInterestedUsers.cs @@ -71,8 +71,7 @@ public override async Task WorkAsync() // Obtem usuários interessados var newBook = newBookMessage.Body; - // TODO: Migrate to async - var interestedUsers = _userService.GetBySolicitedBookCategory(newBook.CategoryId); + var interestedUsers = await _userService.GetBySolicitedBookCategoryAsync(newBook.CategoryId); totalDestinations = interestedUsers.Count; var template = await GetEmailTemplateAsync(newBook.BookId); From 2a3f9d28c05dc5d110e46ac3c919439c835bdb12 Mon Sep 17 00:00:00 2001 From: Henrique Holtz Date: Wed, 12 Jun 2024 19:00:05 -0300 Subject: [PATCH 07/37] perf: IUserService => Turning methods "GetStats" and "ParentAproval" as async and its endpoints --- .../Controllers/AccountController.cs | 4 ++-- .../Book/BooksEmailService.cs | 2 +- .../ShareBook.Service/User/IUserService.cs | 6 ++--- .../ShareBook.Service/User/UserService.cs | 24 +++++++++---------- 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/ShareBook/ShareBook.Api/Controllers/AccountController.cs b/ShareBook/ShareBook.Api/Controllers/AccountController.cs index b264a16d..98b4add9 100644 --- a/ShareBook/ShareBook.Api/Controllers/AccountController.cs +++ b/ShareBook/ShareBook.Api/Controllers/AccountController.cs @@ -237,14 +237,14 @@ public async Task ChangeUserPasswordByHashCodeAsync([FromBody] Ch } [HttpPut("ParentAproval")] - public IActionResult ParentAproval([FromBody] ParentAprovalVM parentAprovalVM) + public async Task ParentAprovalAsync([FromBody] ParentAprovalVM parentAprovalVM) { var ParentHashCodeAproval = parentAprovalVM.ParentHashCodeAproval; if (string.IsNullOrEmpty(ParentHashCodeAproval) || !Guid.TryParse(ParentHashCodeAproval, out _)) throw new ShareBookException("Código inválido."); - _userService.ParentAproval(ParentHashCodeAproval); + await _userService.ParentAprovalAsync(ParentHashCodeAproval); return Ok(); } diff --git a/ShareBook/ShareBook.Service/Book/BooksEmailService.cs b/ShareBook/ShareBook.Service/Book/BooksEmailService.cs index 690726a0..67757cad 100644 --- a/ShareBook/ShareBook.Service/Book/BooksEmailService.cs +++ b/ShareBook/ShareBook.Service/Book/BooksEmailService.cs @@ -78,7 +78,7 @@ public async Task SendEmailNewBookInsertedAsync(Book book) if (book.User == null) book.User = await _userService.FindAsync(book.UserId); - var userStats = _userService.GetStats(book.UserId); + var userStats = await _userService.GetStatsAsync(book.UserId); await SendEmailNewBookInsertedToAdministrators(book, userStats); diff --git a/ShareBook/ShareBook.Service/User/IUserService.cs b/ShareBook/ShareBook.Service/User/IUserService.cs index caea50dc..66e98e59 100644 --- a/ShareBook/ShareBook.Service/User/IUserService.cs +++ b/ShareBook/ShareBook.Service/User/IUserService.cs @@ -19,9 +19,9 @@ public interface IUserService : IBaseService Result ConfirmHashCodePassword(string hashCodePassword); IList GetFacilitators(Guid userIdDonator); IList GetAdmins(); - Task> GetBySolicitedBookCategoryAsync(Guid BookCategoryId); - UserStatsDTO GetStats(Guid? userId); + Task> GetBySolicitedBookCategoryAsync(Guid bookCategoryId); + Task GetStatsAsync(Guid? userId); Result Insert(RegisterUserDTO userDto); - void ParentAproval(string parentHashCodeAproval); + Task ParentAprovalAsync(string parentHashCodeAproval); } } diff --git a/ShareBook/ShareBook.Service/User/UserService.cs b/ShareBook/ShareBook.Service/User/UserService.cs index b3188b22..97a0ee18 100644 --- a/ShareBook/ShareBook.Service/User/UserService.cs +++ b/ShareBook/ShareBook.Service/User/UserService.cs @@ -310,30 +310,30 @@ private User UserCleanup(User user) public async Task> GetBySolicitedBookCategoryAsync(Guid bookCategoryId) => await _userRepository.Get().Where(u => u.AllowSendingEmail && u.BookUsers.Any(bu => bu.Book.CategoryId == bookCategoryId)).ToListAsync(); - public UserStatsDTO GetStats(Guid? userId) + public async Task GetStatsAsync(Guid? userId) { - var user = _userRepository.Find(userId); - var books = _bookRepository.Get().Where(b => b.UserId == userId).ToList(); + var user = await _userRepository.FindAsync(userId); + var books = await _bookRepository.Get().Where(b => b.UserId == userId).ToListAsync(); if (user == null) throw new ShareBookException(ShareBookException.Error.NotFound, "Usuário não encontrado."); var stats = new UserStatsDTO { CreationDate = user.CreationDate, - TotalLate = books.Where(b => b.ChooseDate < DateTime.Today && b.Status == BookStatus.AwaitingDonorDecision).Count(), - TotalOk = books.Where(b => b.Status == BookStatus.WaitingSend || b.Status == BookStatus.Sent || b.Status == BookStatus.Received).Count(), - TotalCanceled = books.Where(b => b.Status == BookStatus.Canceled).Count(), - TotalWaitingApproval = books.Where(b => b.Status == BookStatus.WaitingApproval).Count(), - TotalAvailable = books.Where(b => b.Status == BookStatus.Available).Count(), + TotalLate = books.Count(b => b.ChooseDate < DateTime.Today && b.Status == BookStatus.AwaitingDonorDecision), + TotalOk = books.Count(b => b.Status == BookStatus.WaitingSend || b.Status == BookStatus.Sent || b.Status == BookStatus.Received), + TotalCanceled = books.Count(b => b.Status == BookStatus.Canceled), + TotalWaitingApproval = books.Count(b => b.Status == BookStatus.WaitingApproval), + TotalAvailable = books.Count(b => b.Status == BookStatus.Available), }; return stats; } - public void ParentAproval(string parentHashCodeAproval) + public async Task ParentAprovalAsync(string parentHashCodeAproval) { - var user = _repository.Get() + var user = await _repository.Get() .Where(u => u.ParentHashCodeAproval == parentHashCodeAproval) - .FirstOrDefault(); + .FirstOrDefaultAsync(); if (user == null) throw new ShareBookException(ShareBookException.Error.NotFound, "Nenhum usuário encontrado."); @@ -342,7 +342,7 @@ public void ParentAproval(string parentHashCodeAproval) throw new ShareBookException(ShareBookException.Error.NotFound, "O acesso já foi liberado anteriormente. Tudo certo."); user.ParentAproved = true; - _userRepository.Update(user); + await _userRepository.UpdateAsync(user); _userEmailService.SendEmailParentAprovedNotifyUser(user); } From 34aaec08abd7a35811fcacab913425704d44587a Mon Sep 17 00:00:00 2001 From: Henrique Holtz Date: Wed, 12 Jun 2024 19:05:45 -0300 Subject: [PATCH 08/37] perf: Turning the method "IUserEmailService.SendEmailParentAprovedNotifyUser" as async --- ShareBook/ShareBook.Service/User/IUserEmailService.cs | 2 +- ShareBook/ShareBook.Service/User/UserEmailService.cs | 7 +++---- ShareBook/ShareBook.Service/User/UserService.cs | 2 +- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/ShareBook/ShareBook.Service/User/IUserEmailService.cs b/ShareBook/ShareBook.Service/User/IUserEmailService.cs index 97f89baf..1557a69a 100644 --- a/ShareBook/ShareBook.Service/User/IUserEmailService.cs +++ b/ShareBook/ShareBook.Service/User/IUserEmailService.cs @@ -8,7 +8,7 @@ public interface IUserEmailService { Task SendEmailForgotMyPasswordToUserAsync(User user); void SendEmailRequestParentAproval(RegisterUserDTO userDto, User user); - void SendEmailParentAprovedNotifyUser(User user); + Task SendEmailParentAprovedNotifyUserAsync(User user); void SendEmailAnonymizeNotifyAdms(UserAnonymizeDTO dto); } } diff --git a/ShareBook/ShareBook.Service/User/UserEmailService.cs b/ShareBook/ShareBook.Service/User/UserEmailService.cs index 539507cf..def74b03 100644 --- a/ShareBook/ShareBook.Service/User/UserEmailService.cs +++ b/ShareBook/ShareBook.Service/User/UserEmailService.cs @@ -49,17 +49,16 @@ public void SendEmailRequestParentAproval(RegisterUserDTO userDto, User user) _emailService.Send(userDto.ParentEmail, "Pais", html, title).Wait(); } - public void SendEmailParentAprovedNotifyUser(User user) + public async Task SendEmailParentAprovedNotifyUserAsync(User user) { var vm = new { SharebookLink = _serverSettings.DefaultUrl }; - // TODO: Remove "GetAwaiter().GetResult()" - var html = _emailTemplate.GenerateHtmlFromTemplateAsync("ParentAprovedNotifyUser", vm).GetAwaiter().GetResult(); + var html = await _emailTemplate.GenerateHtmlFromTemplateAsync("ParentAprovedNotifyUser", vm); var title = "Consentimento dos pais"; - _emailService.Send(user.Email, user.Name, html, title).Wait(); + await _emailService.Send(user.Email, user.Name, html, title); } public void SendEmailAnonymizeNotifyAdms(UserAnonymizeDTO dto) diff --git a/ShareBook/ShareBook.Service/User/UserService.cs b/ShareBook/ShareBook.Service/User/UserService.cs index 97a0ee18..f0a8f8e9 100644 --- a/ShareBook/ShareBook.Service/User/UserService.cs +++ b/ShareBook/ShareBook.Service/User/UserService.cs @@ -344,7 +344,7 @@ public async Task ParentAprovalAsync(string parentHashCodeAproval) user.ParentAproved = true; await _userRepository.UpdateAsync(user); - _userEmailService.SendEmailParentAprovedNotifyUser(user); + await _userEmailService.SendEmailParentAprovedNotifyUserAsync(user); } From 993433ba66f3c7f0f9210eb705dae7d82aaf48a6 Mon Sep 17 00:00:00 2001 From: Henrique Holtz Date: Wed, 12 Jun 2024 19:10:52 -0300 Subject: [PATCH 09/37] perf: IUserEmailService && IUserService => Turning methods as async --- .../ShareBook.Api/Controllers/AccountController.cs | 4 ++-- .../ShareBook.Service/User/IUserEmailService.cs | 2 +- ShareBook/ShareBook.Service/User/IUserService.cs | 2 +- .../ShareBook.Service/User/UserEmailService.cs | 8 +++----- ShareBook/ShareBook.Service/User/UserService.cs | 14 +++++++------- 5 files changed, 14 insertions(+), 16 deletions(-) diff --git a/ShareBook/ShareBook.Api/Controllers/AccountController.cs b/ShareBook/ShareBook.Api/Controllers/AccountController.cs index 98b4add9..cf96dc02 100644 --- a/ShareBook/ShareBook.Api/Controllers/AccountController.cs +++ b/ShareBook/ShareBook.Api/Controllers/AccountController.cs @@ -107,9 +107,9 @@ public async Task WhoAccessedMyProfile(Guid userId) [HttpPost("Register")] [ProducesResponseType(typeof(object), 200)] [ProducesResponseType(409)] - public IActionResult Post([FromBody] RegisterUserDTO registerUserDto, [FromServices] SigningConfigurations signingConfigurations, [FromServices] TokenConfigurations tokenConfigurations) + public async Task Post([FromBody] RegisterUserDTO registerUserDto, [FromServices] SigningConfigurations signingConfigurations, [FromServices] TokenConfigurations tokenConfigurations) { - var result = _userService.Insert(registerUserDto); + var result = await _userService.InsertAsync(registerUserDto); if (result.Success) { diff --git a/ShareBook/ShareBook.Service/User/IUserEmailService.cs b/ShareBook/ShareBook.Service/User/IUserEmailService.cs index 1557a69a..8d3b7635 100644 --- a/ShareBook/ShareBook.Service/User/IUserEmailService.cs +++ b/ShareBook/ShareBook.Service/User/IUserEmailService.cs @@ -7,7 +7,7 @@ namespace ShareBook.Service public interface IUserEmailService { Task SendEmailForgotMyPasswordToUserAsync(User user); - void SendEmailRequestParentAproval(RegisterUserDTO userDto, User user); + Task SendEmailRequestParentAprovalAsync(RegisterUserDTO userDto, User user); Task SendEmailParentAprovedNotifyUserAsync(User user); void SendEmailAnonymizeNotifyAdms(UserAnonymizeDTO dto); } diff --git a/ShareBook/ShareBook.Service/User/IUserService.cs b/ShareBook/ShareBook.Service/User/IUserService.cs index 66e98e59..227f58a2 100644 --- a/ShareBook/ShareBook.Service/User/IUserService.cs +++ b/ShareBook/ShareBook.Service/User/IUserService.cs @@ -21,7 +21,7 @@ public interface IUserService : IBaseService IList GetAdmins(); Task> GetBySolicitedBookCategoryAsync(Guid bookCategoryId); Task GetStatsAsync(Guid? userId); - Result Insert(RegisterUserDTO userDto); + Task> InsertAsync(RegisterUserDTO userDto); Task ParentAprovalAsync(string parentHashCodeAproval); } } diff --git a/ShareBook/ShareBook.Service/User/UserEmailService.cs b/ShareBook/ShareBook.Service/User/UserEmailService.cs index def74b03..0ccfe854 100644 --- a/ShareBook/ShareBook.Service/User/UserEmailService.cs +++ b/ShareBook/ShareBook.Service/User/UserEmailService.cs @@ -34,19 +34,17 @@ public async Task SendEmailForgotMyPasswordToUserAsync(User user) await _emailService.Send(user.Email, user.Name, html, title); } - public void SendEmailRequestParentAproval(RegisterUserDTO userDto, User user) + public async Task SendEmailRequestParentAprovalAsync(RegisterUserDTO userDto, User user) { var vm = new { UserName = user.Name, AprovalLink = $"{_serverSettings.DefaultUrl}/consentimento-dos-pais/{user.ParentHashCodeAproval}", }; - // TODO: Remove "GetAwaiter().GetResult()" - var html = _emailTemplate.GenerateHtmlFromTemplateAsync("RequestParentAproval", vm).GetAwaiter().GetResult(); + var html = await _emailTemplate.GenerateHtmlFromTemplateAsync("RequestParentAproval", vm); var title = "Consentimento dos pais"; - // TODO: Remove ".Wait()" - _emailService.Send(userDto.ParentEmail, "Pais", html, title).Wait(); + await _emailService.Send(userDto.ParentEmail, "Pais", html, title); } public async Task SendEmailParentAprovedNotifyUserAsync(User user) diff --git a/ShareBook/ShareBook.Service/User/UserService.cs b/ShareBook/ShareBook.Service/User/UserService.cs index f0a8f8e9..579c439e 100644 --- a/ShareBook/ShareBook.Service/User/UserService.cs +++ b/ShareBook/ShareBook.Service/User/UserService.cs @@ -94,12 +94,12 @@ public Result AuthenticationByEmailAndPassword(User user) return result; } - public Result Insert(RegisterUserDTO userDto) + public async Task> InsertAsync(RegisterUserDTO userDto) { User user = _mapper.Map(userDto); Result resultRecaptcha = _recaptchaService.SimpleValidationRecaptcha(userDto?.RecaptchaReactive); - var result = Validate(user); + var result = await ValidateAsync(user); if (!resultRecaptcha.Success && resultRecaptcha.Messages != null) result.Messages.AddRange(resultRecaptcha.Messages); @@ -108,23 +108,23 @@ public Result Insert(RegisterUserDTO userDto) // Senha forte não é mais obrigatória. - if (_repository.Any(x => x.Email == user.Email)) + if (await _repository.AnyAsync(x => x.Email == user.Email)) throw new ShareBookException("Usuário já possui email cadastrado."); // LGPD - CONSENTIMENTO DOS PAIS. if (userDto.Age < 12) - ParentAprovalStartFlow(userDto, user); + await ParentAprovalStartFlowAsync(userDto, user); user.Email = user.Email.ToLowerInvariant(); if (result.Success) { user = GetUserEncryptedPass(user); - result.Value = UserCleanup(_repository.Insert(user)); + result.Value = UserCleanup(await _repository.InsertAsync(user)); } return result; } - private void ParentAprovalStartFlow(RegisterUserDTO userDto, User user) + private async Task ParentAprovalStartFlowAsync(RegisterUserDTO userDto, User user) { user.ParentAproved = false; user.ParentHashCodeAproval = Guid.NewGuid().ToString(); @@ -132,7 +132,7 @@ private void ParentAprovalStartFlow(RegisterUserDTO userDto, User user) if (string.IsNullOrEmpty(userDto.ParentEmail)) throw new ShareBookException("Menor de idade. Obrigatório informar o email do pai ou responsável."); - _userEmailService.SendEmailRequestParentAproval(userDto, user); + await _userEmailService.SendEmailRequestParentAprovalAsync(userDto, user); } public override async Task> UpdateAsync(User user) From 586f7ecb8f1868b82128666e94e6c15985797ef0 Mon Sep 17 00:00:00 2001 From: Henrique Holtz Date: Wed, 12 Jun 2024 19:13:27 -0300 Subject: [PATCH 10/37] perf: Turning "IUserEmailService.SendEmailAnonymizeNotifyAdms" as async --- ShareBook/ShareBook.Service/Lgpd/LgpdService.cs | 2 +- ShareBook/ShareBook.Service/User/IUserEmailService.cs | 2 +- ShareBook/ShareBook.Service/User/UserEmailService.cs | 7 +++---- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/ShareBook/ShareBook.Service/Lgpd/LgpdService.cs b/ShareBook/ShareBook.Service/Lgpd/LgpdService.cs index 78433589..da40ad44 100644 --- a/ShareBook/ShareBook.Service/Lgpd/LgpdService.cs +++ b/ShareBook/ShareBook.Service/Lgpd/LgpdService.cs @@ -62,7 +62,7 @@ public async Task AnonymizeAsync(UserAnonymizeDTO dto) RemoveLogs(user); // 5 - Notifica os adms. - _userEmailService.SendEmailAnonymizeNotifyAdms(dto); + await _userEmailService.SendEmailAnonymizeNotifyAdmsAsync(dto); // 6 - Enfim salva await _ctx.SaveChangesAsync(); diff --git a/ShareBook/ShareBook.Service/User/IUserEmailService.cs b/ShareBook/ShareBook.Service/User/IUserEmailService.cs index 8d3b7635..61e2d3ed 100644 --- a/ShareBook/ShareBook.Service/User/IUserEmailService.cs +++ b/ShareBook/ShareBook.Service/User/IUserEmailService.cs @@ -9,6 +9,6 @@ public interface IUserEmailService Task SendEmailForgotMyPasswordToUserAsync(User user); Task SendEmailRequestParentAprovalAsync(RegisterUserDTO userDto, User user); Task SendEmailParentAprovedNotifyUserAsync(User user); - void SendEmailAnonymizeNotifyAdms(UserAnonymizeDTO dto); + Task SendEmailAnonymizeNotifyAdmsAsync(UserAnonymizeDTO dto); } } diff --git a/ShareBook/ShareBook.Service/User/UserEmailService.cs b/ShareBook/ShareBook.Service/User/UserEmailService.cs index 0ccfe854..0b799b3f 100644 --- a/ShareBook/ShareBook.Service/User/UserEmailService.cs +++ b/ShareBook/ShareBook.Service/User/UserEmailService.cs @@ -59,12 +59,11 @@ public async Task SendEmailParentAprovedNotifyUserAsync(User user) await _emailService.Send(user.Email, user.Name, html, title); } - public void SendEmailAnonymizeNotifyAdms(UserAnonymizeDTO dto) + public async Task SendEmailAnonymizeNotifyAdmsAsync(UserAnonymizeDTO dto) { - // TODO: Remove "GetAwaiter().GetResult()" - var html = _emailTemplate.GenerateHtmlFromTemplateAsync("AnonymizeNotifyAdms", dto).GetAwaiter().GetResult(); + var html = await _emailTemplate.GenerateHtmlFromTemplateAsync("AnonymizeNotifyAdms", dto); var title = "Anonimização de conta"; - _emailService.SendToAdmins(html, title); + await _emailService.SendToAdmins(html, title); } } } From c57186b22f7888b98153fcedaa22958464a34200 Mon Sep 17 00:00:00 2001 From: Henrique Holtz Date: Wed, 12 Jun 2024 19:16:45 -0300 Subject: [PATCH 11/37] chore: Removing unused method "IBaseService.Get" ("PagedList Get(Expression> order, int page, int itemsPerPage);") --- ShareBook/ShareBook.Service/Generic/BaseService.cs | 3 --- ShareBook/ShareBook.Service/Generic/IBaseService.cs | 6 ------ 2 files changed, 9 deletions(-) diff --git a/ShareBook/ShareBook.Service/Generic/BaseService.cs b/ShareBook/ShareBook.Service/Generic/BaseService.cs index b8de287a..9ec5b628 100644 --- a/ShareBook/ShareBook.Service/Generic/BaseService.cs +++ b/ShareBook/ShareBook.Service/Generic/BaseService.cs @@ -53,9 +53,6 @@ public PagedList Get(Expression> filter, Expr public PagedList Get(Expression> filter, Expression> order, IncludeList includes) => _repository.Get(filter, order, includes); - public PagedList Get(Expression> order, int page, int itemsPerPage) - => _repository.Get(order, page, itemsPerPage); - public PagedList Get(Expression> order, int page, int itemsPerPage, IncludeList includes) => _repository.Get(order, page, itemsPerPage, includes); diff --git a/ShareBook/ShareBook.Service/Generic/IBaseService.cs b/ShareBook/ShareBook.Service/Generic/IBaseService.cs index 2cdae10c..4ad92ba9 100644 --- a/ShareBook/ShareBook.Service/Generic/IBaseService.cs +++ b/ShareBook/ShareBook.Service/Generic/IBaseService.cs @@ -66,12 +66,6 @@ public interface IBaseService where TEntity : class /// PageList with only 1 page and all the items PagedList Get(Expression> filter, Expression> order, IncludeList includes); - /// - /// Get a paged list of the entity, without any filter, on the specified order, without child objects. - /// - /// First Page = 1 - PagedList Get(Expression> order, int page, int itemsPerPage); - /// /// Get a paged list of the entity, without any filter, on the specified order, with the specified child objects. /// From 13e8e74ea0f239755d842d48f6b61792e837c81c Mon Sep 17 00:00:00 2001 From: Henrique Holtz Date: Wed, 12 Jun 2024 19:20:37 -0300 Subject: [PATCH 12/37] chore: IBaseService => Removing unused and syncronous methods --- .../ShareBook.Service/Generic/BaseService.cs | 15 -------- .../ShareBook.Service/Generic/IBaseService.cs | 34 ------------------- 2 files changed, 49 deletions(-) diff --git a/ShareBook/ShareBook.Service/Generic/BaseService.cs b/ShareBook/ShareBook.Service/Generic/BaseService.cs index 9ec5b628..ac3c27b8 100644 --- a/ShareBook/ShareBook.Service/Generic/BaseService.cs +++ b/ShareBook/ShareBook.Service/Generic/BaseService.cs @@ -41,27 +41,12 @@ public TEntity Find(Expression> filter) public async Task FindAsync(IncludeList includes, Expression> filter) => await _repository.FindAsync(includes, filter); - public PagedList Get(Expression> order) - => _repository.Get(order); - - public PagedList Get(Expression> order, IncludeList includes) - => _repository.Get(order, includes); - - public PagedList Get(Expression> filter, Expression> order) - => _repository.Get(filter, order); - - public PagedList Get(Expression> filter, Expression> order, IncludeList includes) - => _repository.Get(filter, order, includes); - public PagedList Get(Expression> order, int page, int itemsPerPage, IncludeList includes) => _repository.Get(order, page, itemsPerPage, includes); public virtual PagedList Get(Expression> filter, Expression> order, int page, int itemsPerPage) => _repository.Get(filter, order, page, itemsPerPage); - public PagedList Get(Expression> filter, Expression> order, int page, int itemsPerPage, IncludeList includes) - => _repository.Get(filter, order, page, itemsPerPage, includes); - public async Task> FormatPagedListAsync(IQueryable query, int page, int itemsPerPage) { var total = await query.CountAsync(); diff --git a/ShareBook/ShareBook.Service/Generic/IBaseService.cs b/ShareBook/ShareBook.Service/Generic/IBaseService.cs index 4ad92ba9..81f08443 100644 --- a/ShareBook/ShareBook.Service/Generic/IBaseService.cs +++ b/ShareBook/ShareBook.Service/Generic/IBaseService.cs @@ -38,34 +38,6 @@ public interface IBaseService where TEntity : class /// In case that more than 1 entity could be returned for the filter specified. Task FindAsync(IncludeList includes, Expression> filter); - /// - /// Get ALL the entities, without filter, on the specified order, without child objects. - /// Use it at your own risk, as the number of data returned could be big. - /// BE CAREFUL: could impact on the perfomance. - /// - /// PageList with only 1 page and all the items - PagedList Get(Expression> order); - - /// - /// Get ALL the entities, without filter, on the specified order, with the specified child objects. - /// Use it at your own risk, as the number of data returned could be big, and the child is loaded too. - /// BE CAREFUL: could impact on the perfomance. - /// - /// PageList with only 1 page and all the items - PagedList Get(Expression> order, IncludeList includes); - - /// - /// Get ALL the entities based on the filter passed, on the specified order, without child objects. - /// - /// PageList with only 1 page and all the items - PagedList Get(Expression> filter, Expression> order); - - /// - /// Get ALL the entities based on the filter passed, on the specified order, with the specified child objects. - /// - /// PageList with only 1 page and all the items - PagedList Get(Expression> filter, Expression> order, IncludeList includes); - /// /// Get a paged list of the entity, without any filter, on the specified order, with the specified child objects. /// @@ -78,12 +50,6 @@ public interface IBaseService where TEntity : class /// First Page = 1 PagedList Get(Expression> filter, Expression> order, int page, int itemsPerPage); - /// - /// Get a paged list of the entity, based on the filter passed, on the specified order, with the specified child objects. - /// - /// First Page = 1 - PagedList Get(Expression> filter, Expression> order, int page, int itemsPerPage, IncludeList includes); - Task> InsertAsync(TEntity entity); Task> UpdateAsync(TEntity entity); Task DeleteAsync(params object[] keyValues); From 2313ea503f6ddc232ee3ba2ed44279475a9b725f Mon Sep 17 00:00:00 2001 From: Henrique Holtz Date: Wed, 12 Jun 2024 19:28:28 -0300 Subject: [PATCH 13/37] perf: Migrating the method "IBaseService.Any" to async --- ShareBook/ShareBook.Service/BookUser/BookUserService.cs | 2 +- ShareBook/ShareBook.Service/Generic/BaseService.cs | 2 +- ShareBook/ShareBook.Service/Generic/IBaseService.cs | 2 +- ShareBook/ShareBook.Test.Unit/Services/BookUserServiceTests.cs | 3 +++ 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/ShareBook/ShareBook.Service/BookUser/BookUserService.cs b/ShareBook/ShareBook.Service/BookUser/BookUserService.cs index fa435ddf..f0a31bf4 100644 --- a/ShareBook/ShareBook.Service/BookUser/BookUserService.cs +++ b/ShareBook/ShareBook.Service/BookUser/BookUserService.cs @@ -72,7 +72,7 @@ public async Task InsertAsync(Guid bookId, string reason) NickName = $"Interessado {bookRequested?.TotalInterested() + 1}" }; - if (!_bookService.Any(x => x.Id == bookUser.BookId)) + if (!await _bookService.AnyAsync(x => x.Id == bookUser.BookId)) throw new ShareBookException(ShareBookException.Error.NotFound); if (await _bookUserRepository.AnyAsync(x => x.UserId == bookUser.UserId && x.BookId == bookUser.BookId)) diff --git a/ShareBook/ShareBook.Service/Generic/BaseService.cs b/ShareBook/ShareBook.Service/Generic/BaseService.cs index ac3c27b8..3d8df84c 100644 --- a/ShareBook/ShareBook.Service/Generic/BaseService.cs +++ b/ShareBook/ShareBook.Service/Generic/BaseService.cs @@ -26,7 +26,7 @@ public BaseService(IRepositoryGeneric repository, IUnitOfWork unitOfWor #region GET - public bool Any(Expression> filter) => _repository.Any(filter); + public async Task AnyAsync(Expression> filter) => await _repository.AnyAsync(filter); public async Task CountAsync(Expression> filter) => await _repository.CountAsync(filter); diff --git a/ShareBook/ShareBook.Service/Generic/IBaseService.cs b/ShareBook/ShareBook.Service/Generic/IBaseService.cs index 81f08443..f62f0cdf 100644 --- a/ShareBook/ShareBook.Service/Generic/IBaseService.cs +++ b/ShareBook/ShareBook.Service/Generic/IBaseService.cs @@ -8,7 +8,7 @@ namespace ShareBook.Service.Generic { public interface IBaseService where TEntity : class { - bool Any(Expression> filter); + Task AnyAsync(Expression> filter); Task CountAsync(Expression> filter); /// diff --git a/ShareBook/ShareBook.Test.Unit/Services/BookUserServiceTests.cs b/ShareBook/ShareBook.Test.Unit/Services/BookUserServiceTests.cs index 63c06c5e..0c1df120 100644 --- a/ShareBook/ShareBook.Test.Unit/Services/BookUserServiceTests.cs +++ b/ShareBook/ShareBook.Test.Unit/Services/BookUserServiceTests.cs @@ -1,5 +1,6 @@ using Microsoft.Extensions.Configuration; using Moq; +using ShareBook.Domain; using ShareBook.Domain.Validators; using ShareBook.Repository; using ShareBook.Repository.UoW; @@ -7,6 +8,7 @@ using ShareBook.Service.Muambator; using ShareBook.Test.Unit.Mocks; using System; +using System.Linq.Expressions; using System.Threading; using System.Threading.Tasks; using Xunit; @@ -44,6 +46,7 @@ public BookUserServiceTests() bookServiceMock.SetReturnsDefault(true); + bookServiceMock.Setup(s => s.AnyAsync(It.IsAny>>())).ReturnsAsync(true); bookServiceMock.Setup(s => s.GetBookWithAllUsersAsync(It.IsAny())).ReturnsAsync(() => { return BookMock.GetLordTheRings(); From 42b25654394a853835d52be5e0d28494c8da5e43 Mon Sep 17 00:00:00 2001 From: Henrique Holtz Date: Wed, 12 Jun 2024 19:33:14 -0300 Subject: [PATCH 14/37] chore: Renaming methods adding the suffix "Async" for async methods --- .../Controllers/AccountController.cs | 2 +- .../Controllers/BookController.cs | 2 +- .../Controllers/OperationsController.cs | 2 +- .../AccessHistory/AccessHistoryRepository.cs | 2 +- .../AccessHistory/IAccessHistoryRepository.cs | 2 +- .../Repository/User/IUserRepository.cs | 2 +- .../Repository/User/UserRepository.cs | 2 +- .../ShareBook.Repository/UoW/UnitOfWork.cs | 1 + .../ShareBook.Service/AWSSQS/IAwsSqsQueue.cs | 10 +++--- .../AccessHistory/AccessHistoryService.cs | 2 +- .../AccessHistory/IAccessHistoryService.cs | 3 +- .../ShareBook.Service/AwsSqs/GenericQueue.cs | 6 ++-- .../ShareBook.Service/Book/BookService.cs | 2 +- .../Book/BooksEmailService.cs | 8 ++--- .../BookUser/BookUserEmailService.cs | 36 +++++++++---------- .../BookUser/BookUserService.cs | 22 ++++++------ .../BookUser/IBookUserService.cs | 2 +- .../BookUser/IBookUsersEmailService.cs | 18 +++++----- .../ContactUs/ContactUsEmailService.cs | 4 +-- .../ShareBook.Service/Email/EmailService.cs | 28 ++++++++------- .../ShareBook.Service/Email/IEmailService.cs | 14 ++++---- .../User/UserEmailService.cs | 8 ++--- .../ShareBook.Service/User/UserService.cs | 2 +- .../Services/ContactUsEmailServiceTests.cs | 10 +++--- .../Jobs/1 - ChooseDateReminder.cs | 2 +- .../Jobs/2 - LateDonationNotification.cs | 6 ++-- .../Jobs/3 - RemoveBookFromShowcase.cs | 2 +- .../Jobs/5 - NewBookGetInterestedUsers.cs | 6 ++-- .../Jobs/6 - MailSupressListUpdate.cs | 2 +- .../Sharebook.Jobs/Jobs/7 - MailSender.cs | 12 +++---- 30 files changed, 110 insertions(+), 110 deletions(-) diff --git a/ShareBook/ShareBook.Api/Controllers/AccountController.cs b/ShareBook/ShareBook.Api/Controllers/AccountController.cs index cf96dc02..75b3fcab 100644 --- a/ShareBook/ShareBook.Api/Controllers/AccountController.cs +++ b/ShareBook/ShareBook.Api/Controllers/AccountController.cs @@ -93,7 +93,7 @@ public async Task WhoAccessedMyProfile(Guid userId) if (userId.Equals(null) || userId.Equals(Guid.Empty)) return BadRequest(ModelState); var whoAccessHistory = _mapper.Map, IEnumerable>( - await _historyRepository.GetWhoAccessedMyProfile(userId)); + await _historyRepository.GetWhoAccessedMyProfileAsync(userId)); if (whoAccessHistory is null) return NotFound(userId); diff --git a/ShareBook/ShareBook.Api/Controllers/BookController.cs b/ShareBook/ShareBook.Api/Controllers/BookController.cs index 7f8d83a9..5977a67d 100644 --- a/ShareBook/ShareBook.Api/Controllers/BookController.cs +++ b/ShareBook/ShareBook.Api/Controllers/BookController.cs @@ -383,7 +383,7 @@ public async Task MainUsers(Guid bookId) var visitor = await _userService.FindAsync(userId); var visitorProfile = GetVisitorProfile(result); - await _accessHistoryService.InsertVisitor(book.User, visitor, visitorProfile); + await _accessHistoryService.InsertVisitorAsync(book.User, visitor, visitorProfile); return Ok(result); diff --git a/ShareBook/ShareBook.Api/Controllers/OperationsController.cs b/ShareBook/ShareBook.Api/Controllers/OperationsController.cs index fee877e8..7da85fc6 100644 --- a/ShareBook/ShareBook.Api/Controllers/OperationsController.cs +++ b/ShareBook/ShareBook.Api/Controllers/OperationsController.cs @@ -83,7 +83,7 @@ public async Task EmailTestAsync([FromBody] EmailTestVM emailVM) if (!ModelState.IsValid) return BadRequest(ModelState); - await _emailService.Test(emailVM.Email, emailVM.Name); + await _emailService.TestAsync(emailVM.Email, emailVM.Name); return Ok(); } diff --git a/ShareBook/ShareBook.Repository/Repository/AccessHistory/AccessHistoryRepository.cs b/ShareBook/ShareBook.Repository/Repository/AccessHistory/AccessHistoryRepository.cs index 7f0c6a30..a1ca6455 100644 --- a/ShareBook/ShareBook.Repository/Repository/AccessHistory/AccessHistoryRepository.cs +++ b/ShareBook/ShareBook.Repository/Repository/AccessHistory/AccessHistoryRepository.cs @@ -10,7 +10,7 @@ namespace ShareBook.Repository { public class AccessHistoryRepository : RepositoryGeneric, IAccessHistoryRepository { public AccessHistoryRepository(ApplicationDbContext context) : base(context) { } - public async Task> GetWhoAccessedMyProfile(Guid userId) { + public async Task> GetWhoAccessedMyProfileAsync(Guid userId) { if (userId.Equals(null)) return null; var list = from u in _context.AccessHistories diff --git a/ShareBook/ShareBook.Repository/Repository/AccessHistory/IAccessHistoryRepository.cs b/ShareBook/ShareBook.Repository/Repository/AccessHistory/IAccessHistoryRepository.cs index 9ca6cc7a..122c3518 100644 --- a/ShareBook/ShareBook.Repository/Repository/AccessHistory/IAccessHistoryRepository.cs +++ b/ShareBook/ShareBook.Repository/Repository/AccessHistory/IAccessHistoryRepository.cs @@ -6,6 +6,6 @@ namespace ShareBook.Repository { public interface IAccessHistoryRepository : IRepositoryGeneric { - Task> GetWhoAccessedMyProfile(Guid userId); + Task> GetWhoAccessedMyProfileAsync(Guid userId); } } \ No newline at end of file diff --git a/ShareBook/ShareBook.Repository/Repository/User/IUserRepository.cs b/ShareBook/ShareBook.Repository/Repository/User/IUserRepository.cs index 4c01fc2f..9d155197 100644 --- a/ShareBook/ShareBook.Repository/Repository/User/IUserRepository.cs +++ b/ShareBook/ShareBook.Repository/Repository/User/IUserRepository.cs @@ -5,6 +5,6 @@ namespace ShareBook.Repository { public interface IUserRepository : IRepositoryGeneric { - Task UpdatePassword(User user); + Task UpdatePasswordAsync(User user); } } diff --git a/ShareBook/ShareBook.Repository/Repository/User/UserRepository.cs b/ShareBook/ShareBook.Repository/Repository/User/UserRepository.cs index eb6d2c8f..438ef096 100644 --- a/ShareBook/ShareBook.Repository/Repository/User/UserRepository.cs +++ b/ShareBook/ShareBook.Repository/Repository/User/UserRepository.cs @@ -9,7 +9,7 @@ public UserRepository(ApplicationDbContext context) : base(context) { } - public async Task UpdatePassword(User user) + public async Task UpdatePasswordAsync(User user) { _dbSet.Update(user); _context.Entry(user).Property(x => x.Password).IsModified = true; diff --git a/ShareBook/ShareBook.Repository/UoW/UnitOfWork.cs b/ShareBook/ShareBook.Repository/UoW/UnitOfWork.cs index 7d1a83b9..0d3e008e 100644 --- a/ShareBook/ShareBook.Repository/UoW/UnitOfWork.cs +++ b/ShareBook/ShareBook.Repository/UoW/UnitOfWork.cs @@ -2,6 +2,7 @@ { public class UnitOfWork : IUnitOfWork { + // TODO: Migrate methods to async private readonly ApplicationDbContext _context; public UnitOfWork(ApplicationDbContext context) => _context = context; diff --git a/ShareBook/ShareBook.Service/AWSSQS/IAwsSqsQueue.cs b/ShareBook/ShareBook.Service/AWSSQS/IAwsSqsQueue.cs index b99c58b6..eb242428 100644 --- a/ShareBook/ShareBook.Service/AWSSQS/IAwsSqsQueue.cs +++ b/ShareBook/ShareBook.Service/AWSSQS/IAwsSqsQueue.cs @@ -1,16 +1,14 @@ -using ShareBook.Domain; -using ShareBook.Service.AwsSqs.Dto; -using System; +using ShareBook.Service.AwsSqs.Dto; using System.Threading.Tasks; namespace ShareBook.Service.AwsSqs { public interface IAwsSqsQueue { - Task SendMessage(T message); + Task SendMessageAsync(T message); - Task> GetMessage(); + Task> GetMessageAsync(); - Task DeleteMessage(string receiptHandle); + Task DeleteMessageAsync(string receiptHandle); } } \ No newline at end of file diff --git a/ShareBook/ShareBook.Service/AccessHistory/AccessHistoryService.cs b/ShareBook/ShareBook.Service/AccessHistory/AccessHistoryService.cs index 40e18a67..7a0abb95 100644 --- a/ShareBook/ShareBook.Service/AccessHistory/AccessHistoryService.cs +++ b/ShareBook/ShareBook.Service/AccessHistory/AccessHistoryService.cs @@ -19,7 +19,7 @@ public AccessHistoryService(IAccessHistoryRepository repository, _accessHistoryRepository = repository; } - public async Task InsertVisitor(User user, User visitor, VisitorProfile profile) { + public async Task InsertVisitorAsync(User user, User visitor, VisitorProfile profile) { var visitorProfile = new AccessHistory(user.Id, visitor.Name, profile); await _accessHistoryRepository.InsertAsync(visitorProfile); diff --git a/ShareBook/ShareBook.Service/AccessHistory/IAccessHistoryService.cs b/ShareBook/ShareBook.Service/AccessHistory/IAccessHistoryService.cs index 75b64767..5df0e479 100644 --- a/ShareBook/ShareBook.Service/AccessHistory/IAccessHistoryService.cs +++ b/ShareBook/ShareBook.Service/AccessHistory/IAccessHistoryService.cs @@ -1,11 +1,10 @@ using System.Threading.Tasks; using ShareBook.Domain; using ShareBook.Domain.Enums; -using ShareBook.Service.Generic; namespace ShareBook.Service { public interface IAccessHistoryService { - Task InsertVisitor(User user, User visitor, VisitorProfile profile); + Task InsertVisitorAsync(User user, User visitor, VisitorProfile profile); } } \ No newline at end of file diff --git a/ShareBook/ShareBook.Service/AwsSqs/GenericQueue.cs b/ShareBook/ShareBook.Service/AwsSqs/GenericQueue.cs index 0b49a8c4..08fb1b93 100644 --- a/ShareBook/ShareBook.Service/AwsSqs/GenericQueue.cs +++ b/ShareBook/ShareBook.Service/AwsSqs/GenericQueue.cs @@ -34,7 +34,7 @@ public GenericQueue(IOptions awsSqsSettings) } } - public async Task SendMessage(T message) + public async Task SendMessageAsync(T message) { if (!_awsSqsSettings.IsActive) { @@ -52,7 +52,7 @@ public async Task SendMessage(T message) await _amazonSQSClient.SendMessageAsync(request); } - public async Task> GetMessage() + public async Task> GetMessageAsync() { if (!_awsSqsSettings.IsActive) { @@ -81,7 +81,7 @@ public async Task> GetMessage() } - public async Task DeleteMessage(string receiptHandle) + public async Task DeleteMessageAsync(string receiptHandle) { if (!_awsSqsSettings.IsActive) { diff --git a/ShareBook/ShareBook.Service/Book/BookService.cs b/ShareBook/ShareBook.Service/Book/BookService.cs index c60d65f5..238f51d8 100644 --- a/ShareBook/ShareBook.Service/Book/BookService.cs +++ b/ShareBook/ShareBook.Service/Book/BookService.cs @@ -65,7 +65,7 @@ public async Task ApproveAsync(Guid bookId, DateTime? chooseDate = null) BookTitle = book.Title, CategoryId = book.CategoryId }; - await _newBookQueue.SendMessage(message); + await _newBookQueue.SendMessageAsync(message); } diff --git a/ShareBook/ShareBook.Service/Book/BooksEmailService.cs b/ShareBook/ShareBook.Service/Book/BooksEmailService.cs index 67757cad..52ec5fe8 100644 --- a/ShareBook/ShareBook.Service/Book/BooksEmailService.cs +++ b/ShareBook/ShareBook.Service/Book/BooksEmailService.cs @@ -50,7 +50,7 @@ public async Task SendEmailBookApprovedAsync(Book book) ChooseDate = book.ChooseDate?.ToString("dd/MM/yyyy") }; var html = await _emailTemplate.GenerateHtmlFromTemplateAsync(BookApprovedTemplate, vm); - await _emailService.Send(book.User.Email, book.User.Name, html, BookApprovedTitle, copyAdmins: true, highPriority: true); + await _emailService.SendAsync(book.User.Email, book.User.Name, html, BookApprovedTitle, copyAdmins: true, highPriority: true); } } @@ -69,7 +69,7 @@ public async Task SendEmailBookReceivedAsync(Book book) }; var htmt = await _emailTemplate.GenerateHtmlFromTemplateAsync(BookReceivedTemplate, vm); - await _emailService.Send(book.User.Email, book.User.Name, htmt, BookReceivedTemplate, copyAdmins: true, highPriority: true); + await _emailService.SendAsync(book.User.Email, book.User.Name, htmt, BookReceivedTemplate, copyAdmins: true, highPriority: true); } } @@ -95,7 +95,7 @@ private async Task SendEmailNewBookInsertedToAdministrators(Book book, UserStats }; var html = await _emailTemplate.GenerateHtmlFromTemplateAsync(NewBookInsertedTemplate, model); - await _emailService.SendToAdmins(html, NewBookInsertedTitle); + await _emailService.SendToAdminsAsync(html, NewBookInsertedTitle); } private async Task SendEmailWaitingApprovalToUser(Book book) @@ -104,7 +104,7 @@ private async Task SendEmailWaitingApprovalToUser(Book book) { var html = await _emailTemplate.GenerateHtmlFromTemplateAsync(WaitingApprovalTemplate, book); - await _emailService.Send(book.User.Email, book.User.Name, html, WaitingApprovalTitle, copyAdmins: false, highPriority: true); + await _emailService.SendAsync(book.User.Email, book.User.Name, html, WaitingApprovalTitle, copyAdmins: false, highPriority: true); } } } diff --git a/ShareBook/ShareBook.Service/BookUser/BookUserEmailService.cs b/ShareBook/ShareBook.Service/BookUser/BookUserEmailService.cs index 0721cecb..10109c65 100644 --- a/ShareBook/ShareBook.Service/BookUser/BookUserEmailService.cs +++ b/ShareBook/ShareBook.Service/BookUser/BookUserEmailService.cs @@ -42,7 +42,7 @@ public BookUserEmailService(IUserService userService, IEmailService emailService _cache = memoryCache; } - public async Task SendEmailBookDonated(BookUser bookUser) + public async Task SendEmailBookDonatedAsync(BookUser bookUser) { var bookDonated = bookUser.Book; if (bookDonated.User == null) @@ -56,11 +56,11 @@ public async Task SendEmailBookDonated(BookUser bookUser) bookUser.User }; var html = await _emailTemplate.GenerateHtmlFromTemplateAsync(BookDonatedTemplate, vm); - await _emailService.Send(bookUser.User.Email, bookUser.User.Name, html, BookDonatedTitle, copyAdmins: false, highPriority: true); + await _emailService.SendAsync(bookUser.User.Email, bookUser.User.Name, html, BookDonatedTitle, copyAdmins: false, highPriority: true); } } - public async Task SendEmailBookDonatedNotifyDonor(Book book, User winner) + public async Task SendEmailBookDonatedNotifyDonorAsync(Book book, User winner) { if (book.User.AllowSendingEmail) { @@ -74,11 +74,11 @@ public async Task SendEmailBookDonatedNotifyDonor(Book book, User winner) var html = await _emailTemplate.GenerateHtmlFromTemplateAsync(BookDonatedTemplateNotifyDonor, vm); // TODO: não enviar cópia para admins quando esse processo estiver bem amadurecido. - await _emailService.Send(book.User.Email, book.User.Name, html, BookDonatedTitleNotifyDonor, copyAdmins: true, highPriority: true); + await _emailService.SendAsync(book.User.Email, book.User.Name, html, BookDonatedTitleNotifyDonor, copyAdmins: true, highPriority: true); } } - public async Task SendEmailBookDonor(BookUser bookUser, Book bookRequested) + public async Task SendEmailBookDonorAsync(BookUser bookUser, Book bookRequested) { // envia no máximo 1 email por hora. Pra não sobrecarregar o doador. if (!MaxEmailsDonorValid(bookRequested)) @@ -112,7 +112,7 @@ public async Task SendEmailBookDonor(BookUser bookUser, Book bookRequested) var html = await _emailTemplate.GenerateHtmlFromTemplateAsync(BookNoticeDonorTemplate, vm); // TODO: remover cópia adm quando esse processo estiver amadurecido. - await _emailService.Send(bookRequested.User.Email, bookRequested.User.Name, html, BookNoticeDonorTitle, copyAdmins: true, highPriority: true); + await _emailService.SendAsync(bookRequested.User.Email, bookRequested.User.Name, html, BookNoticeDonorTitle, copyAdmins: true, highPriority: true); EmailsDonorAddCache(bookRequested); } @@ -153,7 +153,7 @@ private void EmailsDonorAddCache(Book bookRequested) _cache.Set(key, true, cacheOptions); } - public async Task SendEmailBookInterested(BookUser bookUser, Book book) + public async Task SendEmailBookInterestedAsync(BookUser bookUser, Book book) { // lazy load depression if (bookUser.User == null) @@ -176,7 +176,7 @@ public async Task SendEmailBookInterested(BookUser bookUser, Book book) _notificationService.SendNotificationByEmail(bookUser.User.Email, $"Você solicitou o livro {vm.NameBook}", $"Aguarde até o dia {vm.ChooseDate} que será anunciado o ganhador. Boa sorte!"); var html = await _emailTemplate.GenerateHtmlFromTemplateAsync(BookNoticeInterestedTemplate, vm); - await _emailService.Send(bookUser.User.Email, bookUser.User.Name, html, BookNoticeInterestedTitle); + await _emailService.SendAsync(bookUser.User.Email, bookUser.User.Name, html, BookNoticeInterestedTitle); } } @@ -206,7 +206,7 @@ private string GenerateDonatedLocation(User donatedUser) } - public async Task SendEmailDonationDeclined(Book book, BookUser bookUserWinner, List bookUsersDeclined) + public async Task SendEmailDonationDeclinedAsync(Book book, BookUser bookUserWinner, List bookUsersDeclined) { var vm = new { @@ -218,12 +218,12 @@ public async Task SendEmailDonationDeclined(Book book, BookUser bookUserWinner, bookUsersDeclined.ForEach(bookUser => { if (bookUser.User.AllowSendingEmail) - _emailService.Send(bookUser.User.Email, bookUser.User.Name, html, emailSubject).Wait(); + _emailService.SendAsync(bookUser.User.Email, bookUser.User.Name, html, emailSubject).Wait(); }); } - public async Task SendEmailDonationCanceled(Book book, List bookUsers) + public async Task SendEmailDonationCanceledAsync(Book book, List bookUsers) { var vm = new { book }; var html = await _emailTemplate.GenerateHtmlFromTemplateAsync(BookCanceledNoticeUsersTemplate, vm); @@ -231,12 +231,12 @@ public async Task SendEmailDonationCanceled(Book book, List bookUsers) bookUsers.ForEach(bookUser => { if (bookUser.User.AllowSendingEmail) - _emailService.Send(bookUser.User.Email, bookUser.User.Name, html, $"Resultado da doação do livro {book.Title}.").Wait(); + _emailService.SendAsync(bookUser.User.Email, bookUser.User.Name, html, $"Resultado da doação do livro {book.Title}.").Wait(); }); } - public async Task SendEmailBookCanceledToAdminsAndDonor(BookCancelationDTO dto) + public async Task SendEmailBookCanceledToAdminsAndDonorAsync(BookCancelationDTO dto) { var donor = dto.Book.User; @@ -249,10 +249,10 @@ public async Task SendEmailBookCanceledToAdminsAndDonor(BookCancelationDTO dto) }; var html = await _emailTemplate.GenerateHtmlFromTemplateAsync(BookCanceledTemplate, templateData); - _emailService.Send(donor.Email, donor.Name, html, BookCanceledTitle, copyAdmins: true, highPriority: true).Wait(); + _emailService.SendAsync(donor.Email, donor.Name, html, BookCanceledTitle, copyAdmins: true, highPriority: true).Wait(); } - public async Task SendEmailTrackingNumberInformed(BookUser bookUserWinner, Book book) + public async Task SendEmailTrackingNumberInformedAsync(BookUser bookUserWinner, Book book) { if (bookUserWinner.User.AllowSendingEmail) { @@ -265,15 +265,15 @@ public async Task SendEmailTrackingNumberInformed(BookUser bookUserWinner, Book EmailFacilitator = book.UserFacilitator.Email, }; var html = await _emailTemplate.GenerateHtmlFromTemplateAsync(BookTrackingNumberNoticeWinnerTemplate, vm); - await _emailService.Send(bookUserWinner.User.Email, bookUserWinner.User.Name, html, BookTrackingNumberNoticeWinnerTitle, copyAdmins: false, highPriority: true); + await _emailService.SendAsync(bookUserWinner.User.Email, bookUserWinner.User.Name, html, BookTrackingNumberNoticeWinnerTitle, copyAdmins: false, highPriority: true); } } - public async Task SendEmailMaxRequests(Book bookRequested) + public async Task SendEmailMaxRequestsAsync(Book bookRequested) { var subject = "Limite de pedidos"; var body = $"Prezados adms, o livro {bookRequested.Title} atingiu o limite de pedidos e foi removido automaticamente da vitrine. A data de decisão foi configurada pra amanhã. Obrigado."; - await _emailService.SendToAdmins(body, subject); + await _emailService.SendToAdminsAsync(body, subject); } } } diff --git a/ShareBook/ShareBook.Service/BookUser/BookUserService.cs b/ShareBook/ShareBook.Service/BookUser/BookUserService.cs index f0a31bf4..33d080fc 100644 --- a/ShareBook/ShareBook.Service/BookUser/BookUserService.cs +++ b/ShareBook/ShareBook.Service/BookUser/BookUserService.cs @@ -86,8 +86,8 @@ public async Task InsertAsync(Guid bookId, string reason) // Remove da vitrine caso o número de pedidos estiver grande demais. MaxRequestsValidation(bookRequested); - await _bookUsersEmailService.SendEmailBookDonor(bookUser, bookRequested); - await _bookUsersEmailService.SendEmailBookInterested(bookUser, bookRequested); + await _bookUsersEmailService.SendEmailBookDonorAsync(bookUser, bookRequested); + await _bookUsersEmailService.SendEmailBookInterestedAsync(bookUser, bookRequested); } @@ -101,7 +101,7 @@ private void MaxRequestsValidation(Book bookRequested) bookRequested.ChooseDate = DateTime.Today.AddDays(1); _bookRepository.Update(bookRequested); - _bookUsersEmailService.SendEmailMaxRequests(bookRequested); + _bookUsersEmailService.SendEmailMaxRequestsAsync(bookRequested); } public async Task DonateBookAsync(Guid bookId, Guid userId, string note) @@ -137,13 +137,13 @@ public async Task DonateBookAsync(Guid bookId, Guid userId, string note) // não completar o trabalho dela. Talvez tenha a ver com o garbage collector. // avisa o ganhador - await _bookUsersEmailService.SendEmailBookDonated(bookUserAccepted); + await _bookUsersEmailService.SendEmailBookDonatedAsync(bookUserAccepted); // avisa os perdedores :/ - await NotifyInterestedAboutBooksWinner(bookId); + await NotifyInterestedAboutBooksWinnerAsync(bookId); // avisa o doador - await _bookUsersEmailService.SendEmailBookDonatedNotifyDonor(bookUserAccepted.Book, bookUserAccepted.User); + await _bookUsersEmailService.SendEmailBookDonatedNotifyDonorAsync(bookUserAccepted.Book, bookUserAccepted.User); } public async Task> CancelAsync(BookCancelationDTO dto) @@ -160,7 +160,7 @@ public async Task> CancelAsync(BookCancelationDTO dto) await CancelBookUsersAndSendNotificationAsync(dto.Book); await _bookService.UpdateAsync(dto.Book); - await _bookUsersEmailService.SendEmailBookCanceledToAdminsAndDonor(dto); + await _bookUsersEmailService.SendEmailBookCanceledToAdminsAndDonorAsync(dto); return new Result(dto.Book); } @@ -203,7 +203,7 @@ public async Task> GetRequestsByUserAsync(int page, int item return result; } - public async Task NotifyInterestedAboutBooksWinner(Guid bookId) + public async Task NotifyInterestedAboutBooksWinnerAsync(Guid bookId) { //Obter todos os users do livro var bookUsers = await _bookUserRepository.Get() @@ -221,7 +221,7 @@ public async Task NotifyInterestedAboutBooksWinner(Guid bookId) var losersBookUser = bookUsers.Where(bu => bu.Status == DonationStatus.Denied).ToList(); //enviar e-mails - await this._bookUsersEmailService.SendEmailDonationDeclined(book, winnerBookUser, losersBookUser); + await this._bookUsersEmailService.SendEmailDonationDeclinedAsync(book, winnerBookUser, losersBookUser); } public async Task NotifyUsersBookCanceledAsync(Book book) @@ -230,7 +230,7 @@ public async Task NotifyUsersBookCanceledAsync(Book book) .Include(u => u.User) .Where(x => x.BookId == book.Id).ToListAsync(); - await this._bookUsersEmailService.SendEmailDonationCanceled(book, bookUsers); + await this._bookUsersEmailService.SendEmailDonationCanceledAsync(book, bookUsers); } public async Task InformTrackingNumberAsync(Guid bookId, string trackingNumber) @@ -257,7 +257,7 @@ public async Task InformTrackingNumberAsync(Guid bookId, string trackingNumber) if (winnerBookUser.User.AllowSendingEmail) //Envia e-mail para avisar o ganhador do tracking number - await _bookUsersEmailService.SendEmailTrackingNumberInformed(winnerBookUser, book); + await _bookUsersEmailService.SendEmailTrackingNumberInformedAsync(winnerBookUser, book); } /// diff --git a/ShareBook/ShareBook.Service/BookUser/IBookUserService.cs b/ShareBook/ShareBook.Service/BookUser/IBookUserService.cs index 306487d2..79cd046d 100644 --- a/ShareBook/ShareBook.Service/BookUser/IBookUserService.cs +++ b/ShareBook/ShareBook.Service/BookUser/IBookUserService.cs @@ -25,7 +25,7 @@ public interface IBookUserService /// Comunicar os interessados não escolhidos sobre a finalização da doação. e quem ganhou o livro /// /// - Task NotifyInterestedAboutBooksWinner(Guid bookId); + Task NotifyInterestedAboutBooksWinnerAsync(Guid bookId); Task> CancelAsync(BookCancelationDTO dto); diff --git a/ShareBook/ShareBook.Service/BookUser/IBookUsersEmailService.cs b/ShareBook/ShareBook.Service/BookUser/IBookUsersEmailService.cs index b9bd5dc6..4c51b859 100644 --- a/ShareBook/ShareBook.Service/BookUser/IBookUsersEmailService.cs +++ b/ShareBook/ShareBook.Service/BookUser/IBookUsersEmailService.cs @@ -7,22 +7,22 @@ namespace ShareBook.Service { public interface IBookUsersEmailService { - Task SendEmailBookDonated(BookUser bookUser); + Task SendEmailBookDonatedAsync(BookUser bookUser); - Task SendEmailBookDonatedNotifyDonor(Book book, User winner); + Task SendEmailBookDonatedNotifyDonorAsync(Book book, User winner); - Task SendEmailBookDonor(BookUser bookUser, Book bookRequested); + Task SendEmailBookDonorAsync(BookUser bookUser, Book bookRequested); - Task SendEmailBookInterested(BookUser bookUser, Book book); + Task SendEmailBookInterestedAsync(BookUser bookUser, Book book); - Task SendEmailDonationDeclined(Book book, BookUser bookUserWinner, List bookUsersDeclined); + Task SendEmailDonationDeclinedAsync(Book book, BookUser bookUserWinner, List bookUsersDeclined); - Task SendEmailDonationCanceled(Book book, List bookUsers); + Task SendEmailDonationCanceledAsync(Book book, List bookUsers); - Task SendEmailBookCanceledToAdminsAndDonor(BookCancelationDTO dto); + Task SendEmailBookCanceledToAdminsAndDonorAsync(BookCancelationDTO dto); - Task SendEmailTrackingNumberInformed(BookUser bookUserWinner, Book book); + Task SendEmailTrackingNumberInformedAsync(BookUser bookUserWinner, Book book); - Task SendEmailMaxRequests(Book bookRequested); + Task SendEmailMaxRequestsAsync(Book bookRequested); } } diff --git a/ShareBook/ShareBook.Service/ContactUs/ContactUsEmailService.cs b/ShareBook/ShareBook.Service/ContactUs/ContactUsEmailService.cs index db5051b7..0a23fa00 100644 --- a/ShareBook/ShareBook.Service/ContactUs/ContactUsEmailService.cs +++ b/ShareBook/ShareBook.Service/ContactUs/ContactUsEmailService.cs @@ -29,12 +29,12 @@ public async Task SendEmailContactUsAsync(ContactUs contactUs) private async Task SendEmailContactUsToAdministratorAsync(ContactUs contactUs) { var html = await _emailTemplate.GenerateHtmlFromTemplateAsync(ContactUsTemplate, contactUs); - await _emailService.SendToAdmins(html, ContactUsTitle); + await _emailService.SendToAdminsAsync(html, ContactUsTitle); } private async Task SendEmailNotificationToUserAsync(ContactUs contactUs) { var html = await _emailTemplate.GenerateHtmlFromTemplateAsync(ContactUsNotificationTemplate, contactUs); - await _emailService.Send(contactUs.Email, contactUs.Name, html, ContactUsNotificationTitle, copyAdmins: false, highPriority: true); + await _emailService.SendAsync(contactUs.Email, contactUs.Name, html, ContactUsNotificationTitle, copyAdmins: false, highPriority: true); } } } diff --git a/ShareBook/ShareBook.Service/Email/EmailService.cs b/ShareBook/ShareBook.Service/Email/EmailService.cs index cc61d04e..6349dd81 100644 --- a/ShareBook/ShareBook.Service/Email/EmailService.cs +++ b/ShareBook/ShareBook.Service/Email/EmailService.cs @@ -44,22 +44,22 @@ public EmailService(IOptions emailSettings, IUserRepository userR _ctx = ctx; } - public async Task SendToAdmins(string messageText, string subject) + public async Task SendToAdminsAsync(string messageText, string subject) { var firstAdm = _userRepository.Get().Where(u => u.Profile == Domain.Enums.Profile.Administrator).FirstOrDefault(); - await Send(firstAdm.Email, firstAdm.Name, messageText, subject, copyAdmins: true, highPriority: true); + await SendAsync(firstAdm.Email, firstAdm.Name, messageText, subject, copyAdmins: true, highPriority: true); } - public async Task Send(string emailRecipient, string nameRecipient, string messageText, string subject) - => await Send(emailRecipient, nameRecipient, messageText, subject, copyAdmins: false, highPriority: true); + public async Task SendAsync(string emailRecipient, string nameRecipient, string messageText, string subject) + => await SendAsync(emailRecipient, nameRecipient, messageText, subject, copyAdmins: false, highPriority: true); - public async Task Send(string emailRecipient, string nameRecipient, string messageText, string subject, bool copyAdmins = false, bool highPriority = true) + public async Task SendAsync(string emailRecipient, string nameRecipient, string messageText, string subject, bool copyAdmins = false, bool highPriority = true) { var sqsEnabled = bool.Parse(_configuration["AwsSqsSettings:IsActive"]); if (!sqsEnabled) { - await SendSmtp(emailRecipient, nameRecipient, messageText, subject, copyAdmins); + await SendSmtpAsync(emailRecipient, nameRecipient, messageText, subject, copyAdmins); return; } @@ -78,13 +78,13 @@ public async Task Send(string emailRecipient, string nameRecipient, string messa }; if (highPriority) - await _mailSenderHighPriorityQueue.SendMessage(queueMessage); + await _mailSenderHighPriorityQueue.SendMessageAsync(queueMessage); else - await _mailSenderLowPriorityQueue.SendMessage(queueMessage); + await _mailSenderLowPriorityQueue.SendMessageAsync(queueMessage); } - public async Task SendSmtp(string emailRecipient, string nameRecipient, string messageText, string subject, bool copyAdmins) + public async Task SendSmtpAsync(string emailRecipient, string nameRecipient, string messageText, string subject, bool copyAdmins) { var message = FormatEmail(emailRecipient, nameRecipient, messageText, subject, copyAdmins); @@ -122,6 +122,7 @@ private MimeMessage FormatEmail(string emailRecipient, string nameRecipient, str private InternetAddressList FormatEmailGetAdminEmails() { + // TODO: Migrate to async var admins = _userRepository.Get() .Select(u => new User { Email = u.Email, @@ -140,15 +141,16 @@ private InternetAddressList FormatEmailGetAdminEmails() return list; } - public async Task Test(string email, string name) + public async Task TestAsync(string email, string name) { var subject = "Sharebook - teste de email"; var message = $"

Olá {name},

Esse é um email de teste para verificar se o sharebook consegue fazer contato com você. Por favor avise o facilitador quando esse email chegar. Obrigado.

"; - await this.SendSmtp(email, name, message, subject, copyAdmins: false); + await this.SendSmtpAsync(email, name, message, subject, copyAdmins: false); } - public async Task> ProcessBounceMessages() + public async Task> ProcessBounceMessagesAsync() { + // TODO: Improve async/await var log = new List(); if(string.IsNullOrEmpty(_settings.BounceFolder)) @@ -204,7 +206,7 @@ public async Task> ProcessBounceMessages() return null; } - public async Task> GetBounces(IList emails) + public async Task> GetBouncesAsync(IList emails) { return await _ctx.MailBounces.Where(m => emails.Contains(m.Email)).ToListAsync(); } diff --git a/ShareBook/ShareBook.Service/Email/IEmailService.cs b/ShareBook/ShareBook.Service/Email/IEmailService.cs index 9b55c115..cb3435f8 100644 --- a/ShareBook/ShareBook.Service/Email/IEmailService.cs +++ b/ShareBook/ShareBook.Service/Email/IEmailService.cs @@ -6,14 +6,14 @@ namespace ShareBook.Service { public interface IEmailService { - Task SendToAdmins(string messageText, string subject); - Task Send(string emailRecipient, string nameRecipient, string messageText, string subject); - Task Send(string emailRecipient, string nameRecipient, string messageText, string subject, bool copyAdmins, bool highPriority); - Task SendSmtp(string emailRecipient, string nameRecipient, string messageText, string subject, bool copyAdmins); - Task Test(string email, string name); + Task SendToAdminsAsync(string messageText, string subject); + Task SendAsync(string emailRecipient, string nameRecipient, string messageText, string subject); + Task SendAsync(string emailRecipient, string nameRecipient, string messageText, string subject, bool copyAdmins, bool highPriority); + Task SendSmtpAsync(string emailRecipient, string nameRecipient, string messageText, string subject, bool copyAdmins); + Task TestAsync(string email, string name); - Task> ProcessBounceMessages(); - Task> GetBounces(IList emails); + Task> ProcessBounceMessagesAsync(); + Task> GetBouncesAsync(IList emails); bool IsBounce(string email, IList bounces); } } diff --git a/ShareBook/ShareBook.Service/User/UserEmailService.cs b/ShareBook/ShareBook.Service/User/UserEmailService.cs index 0b799b3f..58d6f106 100644 --- a/ShareBook/ShareBook.Service/User/UserEmailService.cs +++ b/ShareBook/ShareBook.Service/User/UserEmailService.cs @@ -31,7 +31,7 @@ public async Task SendEmailForgotMyPasswordToUserAsync(User user) var html = await _emailTemplate.GenerateHtmlFromTemplateAsync("ForgotPasswordTemplate", vm); var title = "Esqueceu sua senha - Sharebook"; - await _emailService.Send(user.Email, user.Name, html, title); + await _emailService.SendAsync(user.Email, user.Name, html, title); } public async Task SendEmailRequestParentAprovalAsync(RegisterUserDTO userDto, User user) @@ -44,7 +44,7 @@ public async Task SendEmailRequestParentAprovalAsync(RegisterUserDTO userDto, Us var html = await _emailTemplate.GenerateHtmlFromTemplateAsync("RequestParentAproval", vm); var title = "Consentimento dos pais"; - await _emailService.Send(userDto.ParentEmail, "Pais", html, title); + await _emailService.SendAsync(userDto.ParentEmail, "Pais", html, title); } public async Task SendEmailParentAprovedNotifyUserAsync(User user) @@ -56,14 +56,14 @@ public async Task SendEmailParentAprovedNotifyUserAsync(User user) var html = await _emailTemplate.GenerateHtmlFromTemplateAsync("ParentAprovedNotifyUser", vm); var title = "Consentimento dos pais"; - await _emailService.Send(user.Email, user.Name, html, title); + await _emailService.SendAsync(user.Email, user.Name, html, title); } public async Task SendEmailAnonymizeNotifyAdmsAsync(UserAnonymizeDTO dto) { var html = await _emailTemplate.GenerateHtmlFromTemplateAsync("AnonymizeNotifyAdms", dto); var title = "Anonimização de conta"; - await _emailService.SendToAdmins(html, title); + await _emailService.SendToAdminsAsync(html, title); } } } diff --git a/ShareBook/ShareBook.Service/User/UserService.cs b/ShareBook/ShareBook.Service/User/UserService.cs index 579c439e..4aabd448 100644 --- a/ShareBook/ShareBook.Service/User/UserService.cs +++ b/ShareBook/ShareBook.Service/User/UserService.cs @@ -192,7 +192,7 @@ public Result ChangeUserPassword(User user, string newPassword) user.ChangePassword(newPassword); user = GetUserEncryptedPass(user); // TODO: Remove "GetAwaiter().GetResult()" - user = _userRepository.UpdatePassword(user).GetAwaiter().GetResult(); + user = _userRepository.UpdatePasswordAsync(user).GetAwaiter().GetResult(); result.Value = UserCleanup(user); return result; diff --git a/ShareBook/ShareBook.Test.Unit/Services/ContactUsEmailServiceTests.cs b/ShareBook/ShareBook.Test.Unit/Services/ContactUsEmailServiceTests.cs index 56d40b3f..aafa2774 100644 --- a/ShareBook/ShareBook.Test.Unit/Services/ContactUsEmailServiceTests.cs +++ b/ShareBook/ShareBook.Test.Unit/Services/ContactUsEmailServiceTests.cs @@ -14,9 +14,9 @@ public class ContactUsEmailServiceTests public ContactUsEmailServiceTests() { - _mockEmailService.Setup(t => t.SendToAdmins(It.IsAny(), It.IsAny())); - _mockEmailService.Setup(t => t.Send(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())); - _mockEmailService.Setup(t => t.Send(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())); + _mockEmailService.Setup(t => t.SendToAdminsAsync(It.IsAny(), It.IsAny())); + _mockEmailService.Setup(t => t.SendAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())); + _mockEmailService.Setup(t => t.SendAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())); _mockEmailTemplate.Setup(t => t.GenerateHtmlFromTemplateAsync(It.IsAny(), It.IsAny())).ReturnsAsync(HtmlMock); } @@ -33,8 +33,8 @@ public async Task SendEmailContactToTheUserAndToAdministrators() ContactUsEmailService service = new ContactUsEmailService(_mockEmailService.Object, _mockEmailTemplate.Object); await service.SendEmailContactUsAsync(contactUs); - _mockEmailService.Verify(s => s.SendToAdmins(HtmlMock, ContactUsEmailService.ContactUsTitle), Times.Once); - _mockEmailService.Verify(s => s.Send(contactUs.Email, contactUs.Name, HtmlMock, ContactUsEmailService.ContactUsNotificationTitle, false, true), Times.Once); + _mockEmailService.Verify(s => s.SendToAdminsAsync(HtmlMock, ContactUsEmailService.ContactUsTitle), Times.Once); + _mockEmailService.Verify(s => s.SendAsync(contactUs.Email, contactUs.Name, HtmlMock, ContactUsEmailService.ContactUsNotificationTitle, false, true), Times.Once); _mockEmailService.VerifyNoOtherCalls(); _mockEmailTemplate.Verify(s => s.GenerateHtmlFromTemplateAsync(It.IsAny(), It.IsAny()), Times.Exactly(2)); _mockEmailTemplate.VerifyNoOtherCalls(); diff --git a/ShareBook/Sharebook.Jobs/Jobs/1 - ChooseDateReminder.cs b/ShareBook/Sharebook.Jobs/Jobs/1 - ChooseDateReminder.cs index 97230e09..50b156e7 100644 --- a/ShareBook/Sharebook.Jobs/Jobs/1 - ChooseDateReminder.cs +++ b/ShareBook/Sharebook.Jobs/Jobs/1 - ChooseDateReminder.cs @@ -80,7 +80,7 @@ private async Task SendEmailAsync(Book book) }; var emailBodyHTML = await _emailTemplate.GenerateHtmlFromTemplateAsync("ChooseDateReminderTemplate", vm); - await _emailService.Send(book.User.Email, book.User.Name, emailBodyHTML, emailSubject, copyAdmins: false, highPriority: true); + await _emailService.SendAsync(book.User.Email, book.User.Name, emailBodyHTML, emailSubject, copyAdmins: false, highPriority: true); } #endregion diff --git a/ShareBook/Sharebook.Jobs/Jobs/2 - LateDonationNotification.cs b/ShareBook/Sharebook.Jobs/Jobs/2 - LateDonationNotification.cs index 2b501978..ddf352bf 100644 --- a/ShareBook/Sharebook.Jobs/Jobs/2 - LateDonationNotification.cs +++ b/ShareBook/Sharebook.Jobs/Jobs/2 - LateDonationNotification.cs @@ -103,7 +103,7 @@ private async Task SendEmailAdminAsync(IList booksLate, BookStatsDTO statu }; var emailBodyHTML = await _emailTemplate.GenerateHtmlFromTemplateAsync("LateDonationNotification", vm); - await _emailService.SendToAdmins(emailBodyHTML, emailSubject); + await _emailService.SendToAdminsAsync(emailBodyHTML, emailSubject); } private string GetWhatsappLink(string phone) @@ -150,7 +150,7 @@ private async Task SendEmailDonatorHardAsync(User donator) var emailSubject = "Doação abandonada no Sharebook. Urgente!"; - await _emailService.Send(donator.Email, donator.Name, html, emailSubject, copyAdmins: true, highPriority: true); + await _emailService.SendAsync(donator.Email, donator.Name, html, emailSubject, copyAdmins: true, highPriority: true); } private async Task SendEmailDonatorSoftAsync(User donator) @@ -163,7 +163,7 @@ private async Task SendEmailDonatorSoftAsync(User donator) var emailSubject = "Lembrete do Sharebook"; - await _emailService.Send(donator.Email, donator.Name, html, emailSubject, copyAdmins: false, highPriority: true); + await _emailService.SendAsync(donator.Email, donator.Name, html, emailSubject, copyAdmins: false, highPriority: true); } #endregion diff --git a/ShareBook/Sharebook.Jobs/Jobs/3 - RemoveBookFromShowcase.cs b/ShareBook/Sharebook.Jobs/Jobs/3 - RemoveBookFromShowcase.cs index 9cfd6aca..f1702ab1 100644 --- a/ShareBook/Sharebook.Jobs/Jobs/3 - RemoveBookFromShowcase.cs +++ b/ShareBook/Sharebook.Jobs/Jobs/3 - RemoveBookFromShowcase.cs @@ -95,7 +95,7 @@ private async Task SendEmailAsync(Book book) }; var emailBodyHTML = await _emailTemplate.GenerateHtmlFromTemplateAsync("ChooseDateRenewTemplate", vm); - await _emailService.Send(book.User.Email, book.User.Name, emailBodyHTML, emailSubject, copyAdmins: false, highPriority: true); + await _emailService.SendAsync(book.User.Email, book.User.Name, emailBodyHTML, emailSubject, copyAdmins: false, highPriority: true); } #endregion diff --git a/ShareBook/Sharebook.Jobs/Jobs/5 - NewBookGetInterestedUsers.cs b/ShareBook/Sharebook.Jobs/Jobs/5 - NewBookGetInterestedUsers.cs index 799c18a5..09ac79da 100644 --- a/ShareBook/Sharebook.Jobs/Jobs/5 - NewBookGetInterestedUsers.cs +++ b/ShareBook/Sharebook.Jobs/Jobs/5 - NewBookGetInterestedUsers.cs @@ -56,7 +56,7 @@ public override async Task WorkAsync() int sendEmailMaxDestinationsPerQueueMessage = GetEmailMaxDestinationsPerQueueMessage(); // 1 - lê a fila de origem - var newBookMessage = await _newBookQueue.GetMessage(); + var newBookMessage = await _newBookQueue.GetMessageAsync(); // fila vazia, não faz nada if (newBookMessage == null) @@ -88,11 +88,11 @@ public override async Task WorkAsync() Destinations = destinations.ToList() }; - await _mailSenderLowPriorityQueue.SendMessage(mailSenderbody); + await _mailSenderLowPriorityQueue.SendMessageAsync(mailSenderbody); } // remove a mensagem da fila de origem - await _newBookQueue.DeleteMessage(newBookMessage.ReceiptHandle); + await _newBookQueue.DeleteMessageAsync(newBookMessage.ReceiptHandle); // finaliza com sucesso return new JobHistory() diff --git a/ShareBook/Sharebook.Jobs/Jobs/6 - MailSupressListUpdate.cs b/ShareBook/Sharebook.Jobs/Jobs/6 - MailSupressListUpdate.cs index 70d6463f..220c19bf 100644 --- a/ShareBook/Sharebook.Jobs/Jobs/6 - MailSupressListUpdate.cs +++ b/ShareBook/Sharebook.Jobs/Jobs/6 - MailSupressListUpdate.cs @@ -28,7 +28,7 @@ public MailSupressListUpdate( public override async Task WorkAsync() { - var log = await _emailService.ProcessBounceMessages(); + var log = await _emailService.ProcessBounceMessagesAsync(); return new JobHistory() { diff --git a/ShareBook/Sharebook.Jobs/Jobs/7 - MailSender.cs b/ShareBook/Sharebook.Jobs/Jobs/7 - MailSender.cs index 12684e30..0d046bda 100644 --- a/ShareBook/Sharebook.Jobs/Jobs/7 - MailSender.cs +++ b/ShareBook/Sharebook.Jobs/Jobs/7 - MailSender.cs @@ -84,7 +84,7 @@ private async Task SendEmailAsync(SharebookMessage sqsMessa var copyAdmins = sqsMessage.Body.CopyAdmins; var emails = destinations.Select(x => x.Email).ToList(); - var bounces = await _emailService.GetBounces(emails); + var bounces = await _emailService.GetBouncesAsync(emails); foreach (var destination in destinations) { @@ -97,7 +97,7 @@ private async Task SendEmailAsync(SharebookMessage sqsMessa string firstName = GetFirstName(destination.Name); var bodyHtml2 = bodyHtml.Replace("{name}", firstName, StringComparison.OrdinalIgnoreCase); - await _emailService.SendSmtp(destination.Email, destination.Name, bodyHtml2, subject, copyAdmins); + await _emailService.SendSmtpAsync(destination.Email, destination.Name, bodyHtml2, subject, copyAdmins); _log.Add($"Enviei um email com SUCESSO para {destination.Email}."); } @@ -124,11 +124,11 @@ private static string GetFirstName(string fullName) private async Task> GetSqsMessageAsync() { - var sqsMessage = await _sqsHighPriority.GetMessage(); + var sqsMessage = await _sqsHighPriority.GetMessageAsync(); _lastQueue = "HighPriority"; if(sqsMessage == null) { - sqsMessage = await _sqsLowPriority.GetMessage(); + sqsMessage = await _sqsLowPriority.GetMessageAsync(); _lastQueue = "LowPriority"; } @@ -145,9 +145,9 @@ private async Task DeleteSqsMessageAsync(SharebookMessage sqsMes _log.Add($"Removendo a mensagem da fila. _lastQueue = {_lastQueue}"); if(_lastQueue == "HighPriority") - await _sqsHighPriority.DeleteMessage(sqsMessage.ReceiptHandle); + await _sqsHighPriority.DeleteMessageAsync(sqsMessage.ReceiptHandle); else - await _sqsLowPriority.DeleteMessage(sqsMessage.ReceiptHandle); + await _sqsLowPriority.DeleteMessageAsync(sqsMessage.ReceiptHandle); } private int GetMaxEmailsToSend() From 37f4d469ae311ce1ba535574227a6b60f4292c53 Mon Sep 17 00:00:00 2001 From: Henrique Holtz Date: Wed, 12 Jun 2024 19:42:18 -0300 Subject: [PATCH 15/37] chore: IRepositoryGeneric => Got rid some unused syncronous methods --- .../Repository/Generic/IRepositoryGeneric.cs | 57 ------------------- .../Repository/Generic/RepositoryGeneric.cs | 17 ------ 2 files changed, 74 deletions(-) diff --git a/ShareBook/ShareBook.Repository/Repository/Generic/IRepositoryGeneric.cs b/ShareBook/ShareBook.Repository/Repository/Generic/IRepositoryGeneric.cs index 54e0b6bb..d8b921dc 100644 --- a/ShareBook/ShareBook.Repository/Repository/Generic/IRepositoryGeneric.cs +++ b/ShareBook/ShareBook.Repository/Repository/Generic/IRepositoryGeneric.cs @@ -36,21 +36,6 @@ public interface IRepositoryGeneric where TEntity : class /// IQueryable Get(); - /// - /// Execute a Find on the DbSet using the . - /// Using this method will return onlye the Entity, without the children. - /// - /// If you want to get the Child Objects too, use the method. - /// - /// - TEntity Find(object keyValue); - - /// - /// Execute a Find on the DbSet using the and the - /// - TEntity Find(IncludeList includes, object keyValue); - /// /// Find in the DbSet an entity that matches the specified filter. /// @@ -60,35 +45,6 @@ public interface IRepositoryGeneric where TEntity : class /// TEntity Find(Expression> filter); - /// - /// Find in the DbSet an entity that matches the specified filter. - /// - /// Includes (child objects) to be returned. - /// Entity with the child objects - /// - /// In case that more than 1 entity could be returned for the filter specified. - /// - TEntity Find(IncludeList includes, Expression> filter); - - /// - /// Get ALL the entities, without filter, on the specified order, without child objects. - /// Use it at your own risk, as the number of data returned could be big. - /// BE CAREFUL: could impact on the perfomance. - /// - /// PageList with only 1 page and all the items - PagedList Get(Expression> order); - - /// - /// Get ALL the entities, without filter, on the specified order, with the specified child objects. - /// - /// Use it at your own risk, as the number of data returned could be big, and the child is - /// loaded too. - /// - /// BE CAREFUL: could impact on the perfomance. - /// - /// PageList with only 1 page and all the items - PagedList Get(Expression> order, IncludeList includes); - /// /// Get ALL the entities based on the filter passed, on the specified order, without child objects. /// @@ -102,13 +58,6 @@ public interface IRepositoryGeneric where TEntity : class /// PageList with only 1 page and all the items PagedList Get(Expression> filter, Expression> order, IncludeList includes); - /// - /// Get a paged list of the entity, without any filter, on the specified order, without - /// child objects. - /// - /// First Page = 1 - PagedList Get(Expression> order, int page, int itemsPerPage); - /// /// Get a paged list of the entity, without any filter, on the specified order, with the /// specified child objects. @@ -130,12 +79,6 @@ public interface IRepositoryGeneric where TEntity : class /// First Page = 1 PagedList Get(Expression> filter, Expression> order, int page, int itemsPerPage, IncludeList includes); - /// - /// Verify if there is any entity that satisfy the specified filter. - /// - /// True in case if there is at least one entity that satisfy the filter. - bool Any(Expression> filter); - TEntity Insert(TEntity entity); TEntity Update(TEntity entity); diff --git a/ShareBook/ShareBook.Repository/Repository/Generic/RepositoryGeneric.cs b/ShareBook/ShareBook.Repository/Repository/Generic/RepositoryGeneric.cs index a6901278..86fa6c7a 100644 --- a/ShareBook/ShareBook.Repository/Repository/Generic/RepositoryGeneric.cs +++ b/ShareBook/ShareBook.Repository/Repository/Generic/RepositoryGeneric.cs @@ -161,29 +161,14 @@ public async Task DeleteAsync(TEntity entity) public IQueryable Get() => _dbSet; - public TEntity Find(object keyValue) => _dbSet.Find(keyValue); - - public TEntity Find(IncludeList includes, object keyValue) => FindAsync(includes, keyValue).GetAwaiter().GetResult(); - public TEntity Find(Expression> filter) => FindAsync(null, filter).GetAwaiter().GetResult(); - public TEntity Find(IncludeList includes, Expression> filter) => FindAsync(includes, filter).GetAwaiter().GetResult(); - - public PagedList Get(Expression> order) - => Get(order, null); - - public PagedList Get(Expression> order, IncludeList includes) - => Get(x => true, order, includes); - public PagedList Get(Expression> filter, Expression> order) => Get(filter, order, null); public PagedList Get(Expression> filter, Expression> order, IncludeList includes) => Get(filter, order, 1, int.MaxValue, includes); - public PagedList Get(Expression> order, int page, int itemsPerPage) - => Get(order, page, itemsPerPage, null); - public PagedList Get(Expression> order, int page, int itemsPerPage, IncludeList includes) => Get(x => true, order, page, itemsPerPage, includes); @@ -193,8 +178,6 @@ public PagedList Get(Expression> filter, Expr public PagedList Get(Expression> filter, Expression> order, int page, int itemsPerPage, IncludeList includes) => GetAsync(filter, order, page, itemsPerPage, includes).GetAwaiter().GetResult(); - public bool Any(Expression> filter) => AnyAsync(filter).GetAwaiter().GetResult(); - public TEntity Insert(TEntity entity) => InsertAsync(entity).GetAwaiter().GetResult(); public TEntity Update(TEntity entity) => UpdateAsync(entity).GetAwaiter().GetResult(); From e2647022674305d17c89c176eff0d920272e256f Mon Sep 17 00:00:00 2001 From: Henrique Holtz Date: Wed, 12 Jun 2024 19:50:27 -0300 Subject: [PATCH 16/37] perf: IUnitOfWork => Turning all methods as async --- ShareBook/ShareBook.Repository/UoW/IUnitOfWork.cs | 9 +++++---- ShareBook/ShareBook.Repository/UoW/UnitOfWork.cs | 15 ++++++++------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/ShareBook/ShareBook.Repository/UoW/IUnitOfWork.cs b/ShareBook/ShareBook.Repository/UoW/IUnitOfWork.cs index 04423d57..5bd905e2 100644 --- a/ShareBook/ShareBook.Repository/UoW/IUnitOfWork.cs +++ b/ShareBook/ShareBook.Repository/UoW/IUnitOfWork.cs @@ -1,11 +1,12 @@ using System; +using System.Threading.Tasks; namespace ShareBook.Repository.UoW { - public interface IUnitOfWork : IDisposable + public interface IUnitOfWork : IAsyncDisposable { - void BeginTransaction(); - void Commit(); - void Rollback(); + Task BeginTransactionAsync(); + Task CommitAsync(); + Task RollbackAsync(); } } diff --git a/ShareBook/ShareBook.Repository/UoW/UnitOfWork.cs b/ShareBook/ShareBook.Repository/UoW/UnitOfWork.cs index 0d3e008e..68d05411 100644 --- a/ShareBook/ShareBook.Repository/UoW/UnitOfWork.cs +++ b/ShareBook/ShareBook.Repository/UoW/UnitOfWork.cs @@ -1,16 +1,17 @@ -namespace ShareBook.Repository.UoW +using System; +using System.Threading.Tasks; + +namespace ShareBook.Repository.UoW { public class UnitOfWork : IUnitOfWork { - // TODO: Migrate methods to async private readonly ApplicationDbContext _context; public UnitOfWork(ApplicationDbContext context) => _context = context; - public void BeginTransaction() => _context.Database.BeginTransaction(); - public void Commit() => _context.Database.CommitTransaction(); - public void Rollback() => _context.Database.RollbackTransaction(); - - public void Dispose() => _context.Database.CurrentTransaction?.Rollback(); + public async Task BeginTransactionAsync() => await _context.Database.BeginTransactionAsync(); + public async Task CommitAsync() => await _context.Database.CommitTransactionAsync(); + public async Task RollbackAsync() => await _context.Database.RollbackTransactionAsync(); + public async ValueTask DisposeAsync() => await _context.Database.CurrentTransaction?.RollbackAsync(); } } From 4c3653263d18ec86eba2411cc996c80cd9d5220c Mon Sep 17 00:00:00 2001 From: Henrique Holtz Date: Wed, 12 Jun 2024 19:57:35 -0300 Subject: [PATCH 17/37] perf: RemovingIRepositoryGeneric.Update to the async version --- .../ShareBook.Api/Controllers/AccountController.cs | 4 ++-- .../Repository/Generic/IRepositoryGeneric.cs | 2 -- .../Repository/Generic/RepositoryGeneric.cs | 2 -- .../ShareBook.Service/BookUser/BookUserService.cs | 8 ++++---- ShareBook/ShareBook.Service/Meetup/MeetupService.cs | 4 ++-- ShareBook/ShareBook.Service/User/IUserService.cs | 2 +- ShareBook/ShareBook.Service/User/UserService.cs | 5 ++--- .../ShareBook.Test.Unit/Services/UserServiceTests.cs | 12 ++++++------ 8 files changed, 17 insertions(+), 22 deletions(-) diff --git a/ShareBook/ShareBook.Api/Controllers/AccountController.cs b/ShareBook/ShareBook.Api/Controllers/AccountController.cs index 75b3fcab..c9bf6755 100644 --- a/ShareBook/ShareBook.Api/Controllers/AccountController.cs +++ b/ShareBook/ShareBook.Api/Controllers/AccountController.cs @@ -126,7 +126,7 @@ public async Task Post([FromBody] RegisterUserDTO registerUserDto [HttpPost("Login")] [ProducesResponseType(typeof(object), 200)] [ProducesResponseType(404)] - public IActionResult Login( + public async Task LoginAsync( [FromBody] LoginUserVM loginUserVM, [FromServices] SigningConfigurations signingConfigurations, [FromServices] TokenConfigurations tokenConfigurations, @@ -142,7 +142,7 @@ public IActionResult Login( throw new ShareBookException("Não é possível fazer login porque seu app está desatualizado. Por favor atualize seu app na loja do Google Play."); var user = _mapper.Map(loginUserVM); - var result = _userService.AuthenticationByEmailAndPassword(user); + var result = await _userService.AuthenticationByEmailAndPasswordAsync(user); if (result.Success) { diff --git a/ShareBook/ShareBook.Repository/Repository/Generic/IRepositoryGeneric.cs b/ShareBook/ShareBook.Repository/Repository/Generic/IRepositoryGeneric.cs index d8b921dc..40ca4427 100644 --- a/ShareBook/ShareBook.Repository/Repository/Generic/IRepositoryGeneric.cs +++ b/ShareBook/ShareBook.Repository/Repository/Generic/IRepositoryGeneric.cs @@ -81,8 +81,6 @@ public interface IRepositoryGeneric where TEntity : class TEntity Insert(TEntity entity); - TEntity Update(TEntity entity); - IQueryable FromSql(string query, object[] parameters); } } \ No newline at end of file diff --git a/ShareBook/ShareBook.Repository/Repository/Generic/RepositoryGeneric.cs b/ShareBook/ShareBook.Repository/Repository/Generic/RepositoryGeneric.cs index 86fa6c7a..6427353e 100644 --- a/ShareBook/ShareBook.Repository/Repository/Generic/RepositoryGeneric.cs +++ b/ShareBook/ShareBook.Repository/Repository/Generic/RepositoryGeneric.cs @@ -180,8 +180,6 @@ public PagedList Get(Expression> filter, Expr public TEntity Insert(TEntity entity) => InsertAsync(entity).GetAwaiter().GetResult(); - public TEntity Update(TEntity entity) => UpdateAsync(entity).GetAwaiter().GetResult(); - #endregion Synchronous } } \ No newline at end of file diff --git a/ShareBook/ShareBook.Service/BookUser/BookUserService.cs b/ShareBook/ShareBook.Service/BookUser/BookUserService.cs index 33d080fc..13204f92 100644 --- a/ShareBook/ShareBook.Service/BookUser/BookUserService.cs +++ b/ShareBook/ShareBook.Service/BookUser/BookUserService.cs @@ -84,14 +84,14 @@ public async Task InsertAsync(Guid bookId, string reason) await _bookUserRepository.InsertAsync(bookUser); // Remove da vitrine caso o número de pedidos estiver grande demais. - MaxRequestsValidation(bookRequested); + await MaxRequestsValidationAsync(bookRequested); await _bookUsersEmailService.SendEmailBookDonorAsync(bookUser, bookRequested); await _bookUsersEmailService.SendEmailBookInterestedAsync(bookUser, bookRequested); } - private void MaxRequestsValidation(Book bookRequested) + private async Task MaxRequestsValidationAsync(Book bookRequested) { var maxRequestsPerBook = int.Parse(_configuration["SharebookSettings:MaxRequestsPerBook"]); if (bookRequested.BookUsers.Count < maxRequestsPerBook) @@ -99,9 +99,9 @@ private void MaxRequestsValidation(Book bookRequested) bookRequested.Status = BookStatus.AwaitingDonorDecision; bookRequested.ChooseDate = DateTime.Today.AddDays(1); - _bookRepository.Update(bookRequested); + await _bookRepository.UpdateAsync(bookRequested); - _bookUsersEmailService.SendEmailMaxRequestsAsync(bookRequested); + await _bookUsersEmailService.SendEmailMaxRequestsAsync(bookRequested); } public async Task DonateBookAsync(Guid bookId, Guid userId, string note) diff --git a/ShareBook/ShareBook.Service/Meetup/MeetupService.cs b/ShareBook/ShareBook.Service/Meetup/MeetupService.cs index d7d1b04a..29e57803 100644 --- a/ShareBook/ShareBook.Service/Meetup/MeetupService.cs +++ b/ShareBook/ShareBook.Service/Meetup/MeetupService.cs @@ -106,8 +106,8 @@ private async Task GetYoutubeVideosAsync() if (updatedMeetups.Any()) { - // TODO: Migrate to async - updatedMeetups.ForEach(m => _repository.Update(m)); + // TODO: Verify if it's possible to use Task.WhenAll or similar + updatedMeetups.ForEach(async(m) => await _repository.UpdateAsync(m)); } return updatedMeetups.Count; diff --git a/ShareBook/ShareBook.Service/User/IUserService.cs b/ShareBook/ShareBook.Service/User/IUserService.cs index 227f58a2..aa051a53 100644 --- a/ShareBook/ShareBook.Service/User/IUserService.cs +++ b/ShareBook/ShareBook.Service/User/IUserService.cs @@ -10,7 +10,7 @@ namespace ShareBook.Service { public interface IUserService : IBaseService { - Result AuthenticationByEmailAndPassword(User user); + Task> AuthenticationByEmailAndPasswordAsync(User user); bool IsValidPassword(User user, string decryptedPass); new Task> UpdateAsync(User user); Result ValidOldPasswordAndChangeUserPassword(User user, string newPassword); diff --git a/ShareBook/ShareBook.Service/User/UserService.cs b/ShareBook/ShareBook.Service/User/UserService.cs index 4aabd448..61a12681 100644 --- a/ShareBook/ShareBook.Service/User/UserService.cs +++ b/ShareBook/ShareBook.Service/User/UserService.cs @@ -46,7 +46,7 @@ public UserService(IUserRepository userRepository, IBookRepository bookRepositor _recaptchaService = recaptchaService; } - public Result AuthenticationByEmailAndPassword(User user) + public async Task> AuthenticationByEmailAndPasswordAsync(User user) { var result = Validate(user, x => x.Email, x => x.Password); @@ -69,8 +69,7 @@ public Result AuthenticationByEmailAndPassword(User user) // persiste última tentativa de login ANTES do SUCESSO ou FALHA pra ter métrica de // verificação de brute force. user.LastLogin = DateTime.Now; - // TODO: Migrate to Async - _userRepository.Update(user); + await _userRepository.UpdateAsync(user); if (!IsValidPassword(user, decryptedPass)) { diff --git a/ShareBook/ShareBook.Test.Unit/Services/UserServiceTests.cs b/ShareBook/ShareBook.Test.Unit/Services/UserServiceTests.cs index 4179432a..2263e064 100644 --- a/ShareBook/ShareBook.Test.Unit/Services/UserServiceTests.cs +++ b/ShareBook/ShareBook.Test.Unit/Services/UserServiceTests.cs @@ -179,10 +179,10 @@ public async Task UpdateUserNotExists() #region Login User [Fact] - public void LoginValidUser() + public async Task LoginValidUser() { var service = new UserService(userRepositoryMock.Object, bookRepositoryMock.Object, unitOfWorkMock.Object, new UserValidator(), mapperMock.Object, userEmailServiceMock.Object, recaptchaServiceMock.Object); - Result result = service.AuthenticationByEmailAndPassword(new User() + Result result = await service.AuthenticationByEmailAndPasswordAsync(new User() { Email = "walter@sharebook.com", Password = "123456" @@ -195,10 +195,10 @@ public void LoginValidUser() } [Fact] - public void LoginInvalidPassword() + public async Task LoginInvalidPassword() { var service = new UserService(userRepositoryMock.Object, bookRepositoryMock.Object, unitOfWorkMock.Object, new UserValidator(), mapperMock.Object, userEmailServiceMock.Object, recaptchaServiceMock.Object); - Result result = service.AuthenticationByEmailAndPassword(new User() + Result result = await service.AuthenticationByEmailAndPasswordAsync(new User() { Email = "walter@sharebook.com", Password = "wrongpassword" @@ -208,10 +208,10 @@ public void LoginInvalidPassword() } [Fact] - public void LoginInvalidEmail() + public async Task LoginInvalidEmail() { var service = new UserService(userRepositoryMock.Object, bookRepositoryMock.Object, unitOfWorkMock.Object, new UserValidator(), mapperMock.Object, userEmailServiceMock.Object, recaptchaServiceMock.Object); - Result result = service.AuthenticationByEmailAndPassword(new User() + Result result = await service.AuthenticationByEmailAndPasswordAsync(new User() { Email = "joao@sharebook.com", Password = "wrongpassword" From 88610e544964dd27cf7ddd9a4a177d329a7ee29d Mon Sep 17 00:00:00 2001 From: Henrique Holtz Date: Thu, 13 Jun 2024 06:35:28 -0300 Subject: [PATCH 18/37] perf: Migrating all usages of "IRepositoryGeneric.Insert" from syncronous to async and removing it --- .../Repository/Generic/IRepositoryGeneric.cs | 2 -- .../Repository/Generic/RepositoryGeneric.cs | 2 -- ShareBook/ShareBook.Service/BookUser/BookUserService.cs | 2 +- ShareBook/ShareBook.Test.Unit/Services/UserServiceTests.cs | 2 +- ShareBook/Sharebook.Jobs/Executor/JobExecutor.cs | 6 +++--- ShareBook/Sharebook.Jobs/Jobs/GenericJob.cs | 6 +++--- 6 files changed, 8 insertions(+), 12 deletions(-) diff --git a/ShareBook/ShareBook.Repository/Repository/Generic/IRepositoryGeneric.cs b/ShareBook/ShareBook.Repository/Repository/Generic/IRepositoryGeneric.cs index 40ca4427..7eaf7f8d 100644 --- a/ShareBook/ShareBook.Repository/Repository/Generic/IRepositoryGeneric.cs +++ b/ShareBook/ShareBook.Repository/Repository/Generic/IRepositoryGeneric.cs @@ -79,8 +79,6 @@ public interface IRepositoryGeneric where TEntity : class /// First Page = 1 PagedList Get(Expression> filter, Expression> order, int page, int itemsPerPage, IncludeList includes); - TEntity Insert(TEntity entity); - IQueryable FromSql(string query, object[] parameters); } } \ No newline at end of file diff --git a/ShareBook/ShareBook.Repository/Repository/Generic/RepositoryGeneric.cs b/ShareBook/ShareBook.Repository/Repository/Generic/RepositoryGeneric.cs index 6427353e..3e7745f2 100644 --- a/ShareBook/ShareBook.Repository/Repository/Generic/RepositoryGeneric.cs +++ b/ShareBook/ShareBook.Repository/Repository/Generic/RepositoryGeneric.cs @@ -178,8 +178,6 @@ public PagedList Get(Expression> filter, Expr public PagedList Get(Expression> filter, Expression> order, int page, int itemsPerPage, IncludeList includes) => GetAsync(filter, order, page, itemsPerPage, includes).GetAwaiter().GetResult(); - public TEntity Insert(TEntity entity) => InsertAsync(entity).GetAwaiter().GetResult(); - #endregion Synchronous } } \ No newline at end of file diff --git a/ShareBook/ShareBook.Service/BookUser/BookUserService.cs b/ShareBook/ShareBook.Service/BookUser/BookUserService.cs index 13204f92..c3d819b2 100644 --- a/ShareBook/ShareBook.Service/BookUser/BookUserService.cs +++ b/ShareBook/ShareBook.Service/BookUser/BookUserService.cs @@ -58,7 +58,7 @@ public IList GetRequestersList(Guid bookId) => .Include(x => x.User).ThenInclude(u => u.BooksDonated) .Where(x => x.BookId == bookId) .OrderBy(x => x.CreationDate) - .ToList(); + .ToList(); // TODO: Migrate to async public async Task InsertAsync(Guid bookId, string reason) { diff --git a/ShareBook/ShareBook.Test.Unit/Services/UserServiceTests.cs b/ShareBook/ShareBook.Test.Unit/Services/UserServiceTests.cs index 2263e064..3a6edcdd 100644 --- a/ShareBook/ShareBook.Test.Unit/Services/UserServiceTests.cs +++ b/ShareBook/ShareBook.Test.Unit/Services/UserServiceTests.cs @@ -46,7 +46,7 @@ public UserServiceTests() //Simula login do usuario Thread.CurrentPrincipal = new UserMock().GetClaimsUser(); - userRepositoryMock.Setup(repo => repo.Insert(It.IsAny())).Returns(() => + userRepositoryMock.Setup(repo => repo.InsertAsync(It.IsAny())).ReturnsAsync(() => { return UserMock.GetGrantee(); }); diff --git a/ShareBook/Sharebook.Jobs/Executor/JobExecutor.cs b/ShareBook/Sharebook.Jobs/Executor/JobExecutor.cs index 09239d63..619fe579 100644 --- a/ShareBook/Sharebook.Jobs/Executor/JobExecutor.cs +++ b/ShareBook/Sharebook.Jobs/Executor/JobExecutor.cs @@ -109,7 +109,7 @@ public async Task ExecuteAsync() // Executor também loga seu histórico. Precisamos de rastreabilidade. _stopwatch.Stop(); var details = String.Join("\n", messages.ToArray()); - LogExecutorAddHistory(success, details); + await LogExecutorAddHistoryAsync(success, details); return new JobExecutorResult() { @@ -118,7 +118,7 @@ public async Task ExecuteAsync() }; } - private void LogExecutorAddHistory(bool success, string details) + private async Task LogExecutorAddHistoryAsync(bool success, string details) { var history = new JobHistory() { @@ -128,7 +128,7 @@ private void LogExecutorAddHistory(bool success, string details) TimeSpentSeconds = ((double)_stopwatch.ElapsedMilliseconds / (double)1000), }; - _jobHistoryRepo.Insert(history); + await _jobHistoryRepo.InsertAsync(history); } // TODO: criar um service pro rollbar e reaproveitar aqui diff --git a/ShareBook/Sharebook.Jobs/Jobs/GenericJob.cs b/ShareBook/Sharebook.Jobs/Jobs/GenericJob.cs index f386eba6..52fbf16b 100644 --- a/ShareBook/Sharebook.Jobs/Jobs/GenericJob.cs +++ b/ShareBook/Sharebook.Jobs/Jobs/GenericJob.cs @@ -93,7 +93,7 @@ public async Task ExecuteAsync() try { BeforeWork(); var history = await WorkAsync(); - AfterWork(history); + await AfterWorkAsync(history); return JobResult.Success; } @@ -120,12 +120,12 @@ protected void BeforeWork() _stopwatch = Stopwatch.StartNew(); } - protected void AfterWork(JobHistory history) + protected async Task AfterWorkAsync(JobHistory history) { _stopwatch.Stop(); history.TimeSpentSeconds = ((double)_stopwatch.ElapsedMilliseconds / (double)1000); - _jobHistoryRepo.Insert(history); + await _jobHistoryRepo.InsertAsync(history); } } From 85a0c818edccf04ef9d75328d03d6d2c05186265 Mon Sep 17 00:00:00 2001 From: Henrique Holtz Date: Thu, 13 Jun 2024 06:54:29 -0300 Subject: [PATCH 19/37] perf: ("IBaseService", "IRepositoryGeneric", "IBaseService") Migrating all methods "Get" to the async version --- .../Controllers/BookController.cs | 6 +++--- .../Controllers/CategoryController.cs | 3 ++- .../Controllers/Generic/BaseController.cs | 4 ++-- .../Controllers/MeetupController.cs | 4 ++-- .../Repository/Generic/IRepositoryGeneric.cs | 21 ++++++------------- .../Repository/Generic/RepositoryGeneric.cs | 18 ++++++---------- .../ShareBook.Service/Book/BookService.cs | 4 ++-- .../ShareBook.Service/Generic/BaseService.cs | 8 +++---- .../ShareBook.Service/Generic/IBaseService.cs | 4 ++-- .../ShareBook.Service/Meetup/MeetupService.cs | 2 +- 10 files changed, 30 insertions(+), 44 deletions(-) diff --git a/ShareBook/ShareBook.Api/Controllers/BookController.cs b/ShareBook/ShareBook.Api/Controllers/BookController.cs index 5977a67d..0e792bbf 100644 --- a/ShareBook/ShareBook.Api/Controllers/BookController.cs +++ b/ShareBook/ShareBook.Api/Controllers/BookController.cs @@ -54,16 +54,16 @@ protected void SetDefault(Expression> defaultOrder) [HttpGet()] [Authorize("Bearer")] [AuthorizationFilter(Permissions.Permission.DonateBook)] - public PagedList GetAll() => Paged(1, 15); + public async Task> GetAllAsync() => await PagedAsync(1, 15); [HttpGet("{page}/{items}")] [Authorize("Bearer")] [AuthorizationFilter(Permissions.Permission.DonateBook)] - public PagedList Paged(int page, int items) + public async Task> PagedAsync(int page, int items) { // TODO: parar de usar esse get complicado e fazer uma query linq/ef tradicional usando // ThenInclude(). fonte: https://stackoverflow.com/questions/10822656/entity-framework-include-multiple-levels-of-properties - var books = _service.Get(x => x.Title, page, items, new IncludeList(x => x.User, x => x.BookUsers, x => x.UserFacilitator)); + var books = await _service.GetAsync(x => x.Title, page, items, new IncludeList(x => x.User, x => x.BookUsers, x => x.UserFacilitator)); var responseVM = _mapper.Map>(books.Items); return new PagedList() diff --git a/ShareBook/ShareBook.Api/Controllers/CategoryController.cs b/ShareBook/ShareBook.Api/Controllers/CategoryController.cs index 62280e96..94a87767 100644 --- a/ShareBook/ShareBook.Api/Controllers/CategoryController.cs +++ b/ShareBook/ShareBook.Api/Controllers/CategoryController.cs @@ -3,6 +3,7 @@ using ShareBook.Domain; using ShareBook.Domain.Common; using ShareBook.Service; +using System.Threading.Tasks; namespace ShareBook.Api.Controllers { @@ -15,6 +16,6 @@ public CategoryController(ICategoryService categoryService, SetDefault(x => x.Name); } - public override PagedList GetAll() => Paged(1, 50); + public override async Task> GetAllAsync() => await PagedAsync(1, 50); } } \ No newline at end of file diff --git a/ShareBook/ShareBook.Api/Controllers/Generic/BaseController.cs b/ShareBook/ShareBook.Api/Controllers/Generic/BaseController.cs index e2459cfc..4bb7f27f 100644 --- a/ShareBook/ShareBook.Api/Controllers/Generic/BaseController.cs +++ b/ShareBook/ShareBook.Api/Controllers/Generic/BaseController.cs @@ -49,10 +49,10 @@ protected void SetDefault(Expression> defaultOrder) } [HttpGet()] - public virtual PagedList GetAll() => Paged(1, 15); + public virtual async Task> GetAllAsync() => await PagedAsync(1, 15); [HttpGet("{page}/{items}")] - public virtual PagedList Paged(int page, int items) => _service.Get(x => true, _defaultOrder, page, items); + public virtual async Task> PagedAsync(int page, int items) => await _service.GetAsync(x => true, _defaultOrder, page, items); [HttpGet("{id}")] public async Task GetByIdAsync(string id) => await _service.FindAsync(new Guid(id)); diff --git a/ShareBook/ShareBook.Api/Controllers/MeetupController.cs b/ShareBook/ShareBook.Api/Controllers/MeetupController.cs index 6fba24f5..6a5b30c8 100644 --- a/ShareBook/ShareBook.Api/Controllers/MeetupController.cs +++ b/ShareBook/ShareBook.Api/Controllers/MeetupController.cs @@ -20,9 +20,9 @@ public MeetupController(IMeetupService meetupService) } [HttpGet] - public PagedList Get(int? page, int? pageSize, bool upcoming = false) + public async Task> GetAsync(int? page, int? pageSize, bool upcoming = false) { - return _meetupService.Get(upcoming ? x => x.Active && x.StartDate > DateTime.Now : x => x.Active && x.StartDate <= DateTime.Now, x => x.StartDate, page ?? 1, pageSize ?? 10); + return await _meetupService.GetAsync(upcoming ? x => x.Active && x.StartDate > DateTime.Now : x => x.Active && x.StartDate <= DateTime.Now, x => x.StartDate, page ?? 1, pageSize ?? 10); } [HttpGet("{id}")] diff --git a/ShareBook/ShareBook.Repository/Repository/Generic/IRepositoryGeneric.cs b/ShareBook/ShareBook.Repository/Repository/Generic/IRepositoryGeneric.cs index 7eaf7f8d..20e1be83 100644 --- a/ShareBook/ShareBook.Repository/Repository/Generic/IRepositoryGeneric.cs +++ b/ShareBook/ShareBook.Repository/Repository/Generic/IRepositoryGeneric.cs @@ -15,10 +15,6 @@ public interface IRepositoryGeneric where TEntity : class Task FindAsync(IncludeList includes, Expression> filter); - Task> GetAsync(Expression> filter, Expression> order, int page, int itemsPerPage); - - Task> GetAsync(Expression> filter, Expression> order, int page, int itemsPerPage, IncludeList includes); - Task CountAsync(Expression> filter); Task AnyAsync(Expression> filter); @@ -45,39 +41,34 @@ public interface IRepositoryGeneric where TEntity : class /// TEntity Find(Expression> filter); + Task> GetAsync(Expression> filter, Expression> order, int page, int itemsPerPage); + /// /// Get ALL the entities based on the filter passed, on the specified order, without child objects. /// /// PageList with only 1 page and all the items - PagedList Get(Expression> filter, Expression> order); + Task> GetAsync(Expression> filter, Expression> order); /// /// Get ALL the entities based on the filter passed, on the specified order, with the /// specified child objects. /// /// PageList with only 1 page and all the items - PagedList Get(Expression> filter, Expression> order, IncludeList includes); + Task> GetAsync(Expression> filter, Expression> order, IncludeList includes); /// /// Get a paged list of the entity, without any filter, on the specified order, with the /// specified child objects. /// /// First Page = 1 - PagedList Get(Expression> order, int page, int itemsPerPage, IncludeList includes); - - /// - /// Get a paged list of the entity, based on the filter passed, on the specified order, - /// without child objects. - /// - /// First Page = 1 - PagedList Get(Expression> filter, Expression> order, int page, int itemsPerPage); + Task> GetAsync(Expression> order, int page, int itemsPerPage, IncludeList includes); /// /// Get a paged list of the entity, based on the filter passed, on the specified order, with /// the specified child objects. /// /// First Page = 1 - PagedList Get(Expression> filter, Expression> order, int page, int itemsPerPage, IncludeList includes); + Task> GetAsync(Expression> filter, Expression> order, int page, int itemsPerPage, IncludeList includes); IQueryable FromSql(string query, object[] parameters); } diff --git a/ShareBook/ShareBook.Repository/Repository/Generic/RepositoryGeneric.cs b/ShareBook/ShareBook.Repository/Repository/Generic/RepositoryGeneric.cs index 3e7745f2..e34aa939 100644 --- a/ShareBook/ShareBook.Repository/Repository/Generic/RepositoryGeneric.cs +++ b/ShareBook/ShareBook.Repository/Repository/Generic/RepositoryGeneric.cs @@ -163,20 +163,14 @@ public async Task DeleteAsync(TEntity entity) public TEntity Find(Expression> filter) => FindAsync(null, filter).GetAwaiter().GetResult(); - public PagedList Get(Expression> filter, Expression> order) - => Get(filter, order, null); + public async Task> GetAsync(Expression> filter, Expression> order) + => await GetAsync(filter, order, null); - public PagedList Get(Expression> filter, Expression> order, IncludeList includes) - => Get(filter, order, 1, int.MaxValue, includes); + public async Task> GetAsync(Expression> filter, Expression> order, IncludeList includes) + => await GetAsync(filter, order, 1, int.MaxValue, includes); - public PagedList Get(Expression> order, int page, int itemsPerPage, IncludeList includes) - => Get(x => true, order, page, itemsPerPage, includes); - - public PagedList Get(Expression> filter, Expression> order, int page, int itemsPerPage) - => Get(filter, order, page, itemsPerPage, null); - - public PagedList Get(Expression> filter, Expression> order, int page, int itemsPerPage, IncludeList includes) - => GetAsync(filter, order, page, itemsPerPage, includes).GetAwaiter().GetResult(); + public async Task> GetAsync(Expression> order, int page, int itemsPerPage, IncludeList includes) + => await GetAsync(x => true, order, page, itemsPerPage, includes); #endregion Synchronous } diff --git a/ShareBook/ShareBook.Service/Book/BookService.cs b/ShareBook/ShareBook.Service/Book/BookService.cs index 238f51d8..898c1349 100644 --- a/ShareBook/ShareBook.Service/Book/BookService.cs +++ b/ShareBook/ShareBook.Service/Book/BookService.cs @@ -297,8 +297,8 @@ public async Task UserRequestedBookAsync(Guid bookId) )); } - public override PagedList Get(Expression> filter, Expression> order, int page, int itemsPerPage) - => base.Get(filter, order, page, itemsPerPage); + public override async Task> GetAsync(Expression> filter, Expression> order, int page, int itemsPerPage) + => await base.GetAsync(filter, order, page, itemsPerPage); public async Task> GetUserDonationsAsync(Guid userId) { diff --git a/ShareBook/ShareBook.Service/Generic/BaseService.cs b/ShareBook/ShareBook.Service/Generic/BaseService.cs index 3d8df84c..5f0fca46 100644 --- a/ShareBook/ShareBook.Service/Generic/BaseService.cs +++ b/ShareBook/ShareBook.Service/Generic/BaseService.cs @@ -41,11 +41,11 @@ public TEntity Find(Expression> filter) public async Task FindAsync(IncludeList includes, Expression> filter) => await _repository.FindAsync(includes, filter); - public PagedList Get(Expression> order, int page, int itemsPerPage, IncludeList includes) - => _repository.Get(order, page, itemsPerPage, includes); + public async Task> GetAsync(Expression> order, int page, int itemsPerPage, IncludeList includes) + => await _repository.GetAsync(order, page, itemsPerPage, includes); - public virtual PagedList Get(Expression> filter, Expression> order, int page, int itemsPerPage) - => _repository.Get(filter, order, page, itemsPerPage); + public virtual async Task> GetAsync(Expression> filter, Expression> order, int page, int itemsPerPage) + => await _repository.GetAsync(filter, order, page, itemsPerPage); public async Task> FormatPagedListAsync(IQueryable query, int page, int itemsPerPage) { diff --git a/ShareBook/ShareBook.Service/Generic/IBaseService.cs b/ShareBook/ShareBook.Service/Generic/IBaseService.cs index f62f0cdf..daf2d98f 100644 --- a/ShareBook/ShareBook.Service/Generic/IBaseService.cs +++ b/ShareBook/ShareBook.Service/Generic/IBaseService.cs @@ -42,13 +42,13 @@ public interface IBaseService where TEntity : class /// Get a paged list of the entity, without any filter, on the specified order, with the specified child objects. /// /// First Page = 1 - PagedList Get(Expression> order, int page, int itemsPerPage, IncludeList includes); + Task> GetAsync(Expression> order, int page, int itemsPerPage, IncludeList includes); /// /// Get a paged list of the entity, based on the filter passed, on the specified order, without child objects. /// /// First Page = 1 - PagedList Get(Expression> filter, Expression> order, int page, int itemsPerPage); + Task> GetAsync(Expression> filter, Expression> order, int page, int itemsPerPage); Task> InsertAsync(TEntity entity); Task> UpdateAsync(TEntity entity); diff --git a/ShareBook/ShareBook.Service/Meetup/MeetupService.cs b/ShareBook/ShareBook.Service/Meetup/MeetupService.cs index 29e57803..9ab90afb 100644 --- a/ShareBook/ShareBook.Service/Meetup/MeetupService.cs +++ b/ShareBook/ShareBook.Service/Meetup/MeetupService.cs @@ -75,7 +75,7 @@ private async Task SyncMeetupParticipantsListAsync(IList logs) private async Task GetYoutubeVideosAsync() { - var meetups = _repository.Get(x => x.YoutubeUrl == null, x => x.StartDate); + var meetups = await _repository.GetAsync(x => x.YoutubeUrl == null, x => x.StartDate); if (meetups.TotalItems == 0) return 0; From f3eeaa7dab7efe04a309d3c753a75797990f1846 Mon Sep 17 00:00:00 2001 From: Henrique Holtz Date: Thu, 13 Jun 2024 06:58:03 -0300 Subject: [PATCH 20/37] perf: IBaseService.Find => Migrate to async --- ShareBook/ShareBook.Api/Controllers/MeetupController.cs | 7 +++---- ShareBook/ShareBook.Service/Generic/BaseService.cs | 4 ++-- ShareBook/ShareBook.Service/Generic/IBaseService.cs | 2 +- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/ShareBook/ShareBook.Api/Controllers/MeetupController.cs b/ShareBook/ShareBook.Api/Controllers/MeetupController.cs index 6a5b30c8..24004cc7 100644 --- a/ShareBook/ShareBook.Api/Controllers/MeetupController.cs +++ b/ShareBook/ShareBook.Api/Controllers/MeetupController.cs @@ -26,13 +26,12 @@ public async Task> GetAsync(int? page, int? pageSize, bool upc } [HttpGet("{id}")] - public IActionResult Get(string id) + public async Task GetAsync(string id) { if (!Guid.TryParse(id, out var meetupId)) - { BadRequest(); - } - var meetup = _meetupService.Find(x => x.Id == meetupId); + + var meetup = await _meetupService.FindAsync(x => x.Id == meetupId); return meetup != null ? Ok(meetup) : NotFound(); } diff --git a/ShareBook/ShareBook.Service/Generic/BaseService.cs b/ShareBook/ShareBook.Service/Generic/BaseService.cs index 5f0fca46..c46dd723 100644 --- a/ShareBook/ShareBook.Service/Generic/BaseService.cs +++ b/ShareBook/ShareBook.Service/Generic/BaseService.cs @@ -36,8 +36,8 @@ public virtual async Task FindAsync(object keyValue) public virtual async Task FindAsync(IncludeList includes, object keyValue) => await _repository.FindAsync(includes, keyValue); - public TEntity Find(Expression> filter) - => _repository.Find(filter); + public async Task FindAsync(Expression> filter) + => await _repository.FindAsync(filter); public async Task FindAsync(IncludeList includes, Expression> filter) => await _repository.FindAsync(includes, filter); diff --git a/ShareBook/ShareBook.Service/Generic/IBaseService.cs b/ShareBook/ShareBook.Service/Generic/IBaseService.cs index daf2d98f..86292999 100644 --- a/ShareBook/ShareBook.Service/Generic/IBaseService.cs +++ b/ShareBook/ShareBook.Service/Generic/IBaseService.cs @@ -28,7 +28,7 @@ public interface IBaseService where TEntity : class /// /// Entity with the child objects /// In case that more than 1 entity could be returned for the filter specified. - TEntity Find(Expression> filter); + Task FindAsync(Expression> filter); /// /// Find in the DbSet an entity that matches the specified filter. From 97bd184ee1a1f44a0512fe8efd2e85234c5dcb8b Mon Sep 17 00:00:00 2001 From: Henrique Holtz Date: Thu, 13 Jun 2024 07:02:39 -0300 Subject: [PATCH 21/37] perf: Migrating "IRepositoryGeneric.Find" to async (includes migrating "IUserService.ConfirmHashCodePassword" to async) --- ShareBook/ShareBook.Api/Controllers/AccountController.cs | 2 +- .../Repository/Generic/IRepositoryGeneric.cs | 2 +- .../Repository/Generic/RepositoryGeneric.cs | 2 +- ShareBook/ShareBook.Service/User/IUserService.cs | 2 +- ShareBook/ShareBook.Service/User/UserService.cs | 8 ++++---- .../ShareBook.Test.Unit/Services/UserServiceTests.cs | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/ShareBook/ShareBook.Api/Controllers/AccountController.cs b/ShareBook/ShareBook.Api/Controllers/AccountController.cs index c9bf6755..931d72e6 100644 --- a/ShareBook/ShareBook.Api/Controllers/AccountController.cs +++ b/ShareBook/ShareBook.Api/Controllers/AccountController.cs @@ -221,7 +221,7 @@ public Result ChangePassword([FromBody] ChangePasswordUserVM changePasswor [ProducesResponseType(404)] public async Task ChangeUserPasswordByHashCodeAsync([FromBody] ChangeUserPasswordByHashCodeVM changeUserPasswordByHashCodeVM) { - var result = _userService.ConfirmHashCodePassword(changeUserPasswordByHashCodeVM.HashCodePassword); + var result = await _userService.ConfirmHashCodePasswordAsync(changeUserPasswordByHashCodeVM.HashCodePassword); if (!result.Success) return NotFound(result); var newPassword = changeUserPasswordByHashCodeVM.NewPassword; diff --git a/ShareBook/ShareBook.Repository/Repository/Generic/IRepositoryGeneric.cs b/ShareBook/ShareBook.Repository/Repository/Generic/IRepositoryGeneric.cs index 20e1be83..daa4b3a6 100644 --- a/ShareBook/ShareBook.Repository/Repository/Generic/IRepositoryGeneric.cs +++ b/ShareBook/ShareBook.Repository/Repository/Generic/IRepositoryGeneric.cs @@ -39,7 +39,7 @@ public interface IRepositoryGeneric where TEntity : class /// /// In case that more than 1 entity could be returned for the filter specified. /// - TEntity Find(Expression> filter); + Task FindAsync(Expression> filter); Task> GetAsync(Expression> filter, Expression> order, int page, int itemsPerPage); diff --git a/ShareBook/ShareBook.Repository/Repository/Generic/RepositoryGeneric.cs b/ShareBook/ShareBook.Repository/Repository/Generic/RepositoryGeneric.cs index e34aa939..d99feebf 100644 --- a/ShareBook/ShareBook.Repository/Repository/Generic/RepositoryGeneric.cs +++ b/ShareBook/ShareBook.Repository/Repository/Generic/RepositoryGeneric.cs @@ -161,7 +161,7 @@ public async Task DeleteAsync(TEntity entity) public IQueryable Get() => _dbSet; - public TEntity Find(Expression> filter) => FindAsync(null, filter).GetAwaiter().GetResult(); + public async Task FindAsync(Expression> filter) => await FindAsync(null, filter); public async Task> GetAsync(Expression> filter, Expression> order) => await GetAsync(filter, order, null); diff --git a/ShareBook/ShareBook.Service/User/IUserService.cs b/ShareBook/ShareBook.Service/User/IUserService.cs index aa051a53..b9a3db0f 100644 --- a/ShareBook/ShareBook.Service/User/IUserService.cs +++ b/ShareBook/ShareBook.Service/User/IUserService.cs @@ -16,7 +16,7 @@ public interface IUserService : IBaseService Result ValidOldPasswordAndChangeUserPassword(User user, string newPassword); Result ChangeUserPassword(User user, string newPassword); Task GenerateHashCodePasswordAndSendEmailToUserAsync(string email); - Result ConfirmHashCodePassword(string hashCodePassword); + Task ConfirmHashCodePasswordAsync(string hashCodePassword); IList GetFacilitators(Guid userIdDonator); IList GetAdmins(); Task> GetBySolicitedBookCategoryAsync(Guid bookCategoryId); diff --git a/ShareBook/ShareBook.Service/User/UserService.cs b/ShareBook/ShareBook.Service/User/UserService.cs index 61a12681..06a85a66 100644 --- a/ShareBook/ShareBook.Service/User/UserService.cs +++ b/ShareBook/ShareBook.Service/User/UserService.cs @@ -52,7 +52,7 @@ public async Task> AuthenticationByEmailAndPasswordAsync(User user) string decryptedPass = user.Password; - user = _repository.Find(e => e.Email == user.Email); + user = await _repository.FindAsync(e => e.Email == user.Email); if (user == null) { @@ -200,7 +200,7 @@ public Result ChangeUserPassword(User user, string newPassword) public async Task GenerateHashCodePasswordAndSendEmailToUserAsync(string email) { var result = new Result(); - var user = _repository.Find(e => e.Email == email); + var user = await _repository.FindAsync(e => e.Email == email); if (user == null) { @@ -215,11 +215,11 @@ public async Task GenerateHashCodePasswordAndSendEmailToUserAsync(string return result; } - public Result ConfirmHashCodePassword(string hashCodePassword) + public async Task ConfirmHashCodePasswordAsync(string hashCodePassword) { var result = new Result(); - var userConfirmedHashCodePassword = _repository.Find(e => e.HashCodePassword.Equals(hashCodePassword)); + var userConfirmedHashCodePassword = await _repository.FindAsync(e => e.HashCodePassword.Equals(hashCodePassword)); if (userConfirmedHashCodePassword == null) result.Messages.Add("Hash code não encontrado."); diff --git a/ShareBook/ShareBook.Test.Unit/Services/UserServiceTests.cs b/ShareBook/ShareBook.Test.Unit/Services/UserServiceTests.cs index 3a6edcdd..c799d891 100644 --- a/ShareBook/ShareBook.Test.Unit/Services/UserServiceTests.cs +++ b/ShareBook/ShareBook.Test.Unit/Services/UserServiceTests.cs @@ -56,7 +56,7 @@ public UserServiceTests() return UserMock.GetGrantee(); }); - userRepositoryMock.Setup(repo => repo.Find(It.IsAny>>())).Returns(() => + userRepositoryMock.Setup(repo => repo.FindAsync(It.IsAny>>())).ReturnsAsync(() => { return UserMock.GetGrantee(); }); From 11816c465d28f678d1e843dbb4f69d5333fb45f7 Mon Sep 17 00:00:00 2001 From: Henrique Holtz Date: Thu, 13 Jun 2024 07:09:06 -0300 Subject: [PATCH 22/37] perf: IBookUserService => Migrating methods "GetGranteeUsersByBookId" and "GetRequestersList" to async including its usages --- .../Controllers/BookController.cs | 4 ++-- .../Repository/Generic/RepositoryGeneric.cs | 1 - .../BookUser/BookUserService.cs | 24 +++++++++---------- .../BookUser/IBookUserService.cs | 4 ++-- 4 files changed, 16 insertions(+), 17 deletions(-) diff --git a/ShareBook/ShareBook.Api/Controllers/BookController.cs b/ShareBook/ShareBook.Api/Controllers/BookController.cs index 0e792bbf..6fa21ba1 100644 --- a/ShareBook/ShareBook.Api/Controllers/BookController.cs +++ b/ShareBook/ShareBook.Api/Controllers/BookController.cs @@ -125,7 +125,7 @@ public IList FreightOptions() [Authorize("Bearer")] [HttpGet("GranteeUsersByBookId/{bookId}")] [AuthorizationFilter(Permissions.Permission.DonateBook)] - public IList GetGranteeUsersByBookId(string bookId) => _bookUserService.GetGranteeUsersByBookId(new Guid(bookId)); + public async Task> GetGranteeUsersByBookIdAsync(string bookId) => await _bookUserService.GetGranteeUsersByBookIdAsync(new Guid(bookId)); [Authorize("Bearer")] [HttpGet("RequestersList/{bookId}")] @@ -133,7 +133,7 @@ public async Task GetRequestersListAsync(Guid bookId) { if (!await _IsBookOwnerAsync(bookId)) return Unauthorized(); - var requesters = _bookUserService.GetRequestersList(bookId); + var requesters = await _bookUserService.GetRequestersListAsync(bookId); var requestersVM = _mapper.Map>(requesters); return Ok(requestersVM); diff --git a/ShareBook/ShareBook.Repository/Repository/Generic/RepositoryGeneric.cs b/ShareBook/ShareBook.Repository/Repository/Generic/RepositoryGeneric.cs index d99feebf..3139f063 100644 --- a/ShareBook/ShareBook.Repository/Repository/Generic/RepositoryGeneric.cs +++ b/ShareBook/ShareBook.Repository/Repository/Generic/RepositoryGeneric.cs @@ -10,7 +10,6 @@ namespace ShareBook.Repository { - // TODO: Remove all uses of "GetAwaiter().GetResult()" to be trully async public class RepositoryGeneric : IRepositoryGeneric where TEntity : class { protected readonly ApplicationDbContext _context; diff --git a/ShareBook/ShareBook.Service/BookUser/BookUserService.cs b/ShareBook/ShareBook.Service/BookUser/BookUserService.cs index c3d819b2..2919c5f6 100644 --- a/ShareBook/ShareBook.Service/BookUser/BookUserService.cs +++ b/ShareBook/ShareBook.Service/BookUser/BookUserService.cs @@ -46,19 +46,19 @@ public BookUserService( _configuration = configuration; } - public IList GetGranteeUsersByBookId(Guid bookId) => - _bookUserRepository.Get().Include(x => x.User) + public async Task> GetGranteeUsersByBookIdAsync(Guid bookId) => + await _bookUserRepository.Get().Include(x => x.User) .Where(x => x.BookId == bookId && x.Status == DonationStatus.WaitingAction) - .Select(x => x.User.Cleanup()).ToList(); - - public IList GetRequestersList(Guid bookId) => - _bookUserRepository.Get() - .Include(x => x.User).ThenInclude(u => u.Address) - .Include(x => x.User).ThenInclude(u => u.BookUsers) - .Include(x => x.User).ThenInclude(u => u.BooksDonated) - .Where(x => x.BookId == bookId) - .OrderBy(x => x.CreationDate) - .ToList(); // TODO: Migrate to async + .Select(x => x.User.Cleanup()).ToListAsync(); + + public async Task> GetRequestersListAsync(Guid bookId) => + await _bookUserRepository.Get() + .Include(x => x.User).ThenInclude(u => u.Address) + .Include(x => x.User).ThenInclude(u => u.BookUsers) + .Include(x => x.User).ThenInclude(u => u.BooksDonated) + .Where(x => x.BookId == bookId) + .OrderBy(x => x.CreationDate) + .ToListAsync(); public async Task InsertAsync(Guid bookId, string reason) { diff --git a/ShareBook/ShareBook.Service/BookUser/IBookUserService.cs b/ShareBook/ShareBook.Service/BookUser/IBookUserService.cs index 79cd046d..a6d94fb2 100644 --- a/ShareBook/ShareBook.Service/BookUser/IBookUserService.cs +++ b/ShareBook/ShareBook.Service/BookUser/IBookUserService.cs @@ -11,9 +11,9 @@ public interface IBookUserService { Task InsertAsync(Guid bookId, string reason); - IList GetGranteeUsersByBookId(Guid bookId); + Task> GetGranteeUsersByBookIdAsync(Guid bookId); - IList GetRequestersList(Guid bookId); + Task> GetRequestersListAsync(Guid bookId); Task DonateBookAsync(Guid bookId, Guid userId, string note); From 2b69228889235cbc0d3f56799e8cd93096efcaf0 Mon Sep 17 00:00:00 2001 From: Henrique Holtz Date: Thu, 13 Jun 2024 07:11:16 -0300 Subject: [PATCH 23/37] chore: "BookUserService.CancelAsync" => Removing additional and unused call --- ShareBook/ShareBook.Service/BookUser/BookUserService.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/ShareBook/ShareBook.Service/BookUser/BookUserService.cs b/ShareBook/ShareBook.Service/BookUser/BookUserService.cs index 2919c5f6..a769d4f2 100644 --- a/ShareBook/ShareBook.Service/BookUser/BookUserService.cs +++ b/ShareBook/ShareBook.Service/BookUser/BookUserService.cs @@ -151,9 +151,6 @@ public async Task> CancelAsync(BookCancelationDTO dto) if (dto.Book == null) throw new ShareBookException(ShareBookException.Error.NotFound); - // TODO: Verify if we can remove this call - var bookUsers = await _bookUserRepository.Get().Where(x => x.BookId == dto.Book.Id).ToListAsync(); - dto.Book.ChooseDate = null; dto.Book.Status = BookStatus.Canceled; From a60c8fa3975cd83db63c2d5089404ac8deb7a94e Mon Sep 17 00:00:00 2001 From: Henrique Holtz Date: Thu, 13 Jun 2024 07:22:43 -0300 Subject: [PATCH 24/37] perf: EmailService => Improving async/await usages --- .../ShareBook.Service/Email/EmailService.cs | 52 +++++++++---------- 1 file changed, 25 insertions(+), 27 deletions(-) diff --git a/ShareBook/ShareBook.Service/Email/EmailService.cs b/ShareBook/ShareBook.Service/Email/EmailService.cs index 6349dd81..da2a9f60 100644 --- a/ShareBook/ShareBook.Service/Email/EmailService.cs +++ b/ShareBook/ShareBook.Service/Email/EmailService.cs @@ -46,7 +46,7 @@ public EmailService(IOptions emailSettings, IUserRepository userR public async Task SendToAdminsAsync(string messageText, string subject) { - var firstAdm = _userRepository.Get().Where(u => u.Profile == Domain.Enums.Profile.Administrator).FirstOrDefault(); + var firstAdm = await _userRepository.Get().Where(u => u.Profile == Domain.Enums.Profile.Administrator).FirstOrDefaultAsync(); await SendAsync(firstAdm.Email, firstAdm.Name, messageText, subject, copyAdmins: true, highPriority: true); } @@ -86,7 +86,7 @@ public async Task SendAsync(string emailRecipient, string nameRecipient, string public async Task SendSmtpAsync(string emailRecipient, string nameRecipient, string messageText, string subject, bool copyAdmins) { - var message = FormatEmail(emailRecipient, nameRecipient, messageText, subject, copyAdmins); + var message = await FormatEmailAsync(emailRecipient, nameRecipient, messageText, subject, copyAdmins); var client = new SmtpClient(); @@ -94,13 +94,13 @@ public async Task SendSmtpAsync(string emailRecipient, string nameRecipient, str client.ServerCertificateValidationCallback = (s, c, h, e) => true; client.CheckCertificateRevocation = false; - client.Connect(_settings.HostName, _settings.Port, _settings.UseSSL); - client.Authenticate(_settings.Username, _settings.Password); + await client.ConnectAsync(_settings.HostName, _settings.Port, _settings.UseSSL); + await client.AuthenticateAsync(_settings.Username, _settings.Password); await client.SendAsync(message); - client.Disconnect(true); + await client.DisconnectAsync(true); } - private MimeMessage FormatEmail(string emailRecipient, string nameRecipient, string messageText, string subject, bool copyAdmins) + private async Task FormatEmailAsync(string emailRecipient, string nameRecipient, string messageText, string subject, bool copyAdmins) { var message = new MimeMessage(); message.From.Add(new MailboxAddress("Sharebook", "contato@sharebook.com.br")); @@ -108,7 +108,7 @@ private MimeMessage FormatEmail(string emailRecipient, string nameRecipient, str if (copyAdmins) { - var adminsEmails = FormatEmailGetAdminEmails(); + var adminsEmails = await FormatEmailGetAdminEmailsAsync(); message.Cc.AddRange(adminsEmails); } @@ -120,17 +120,16 @@ private MimeMessage FormatEmail(string emailRecipient, string nameRecipient, str return message; } - private InternetAddressList FormatEmailGetAdminEmails() + private async Task FormatEmailGetAdminEmailsAsync() { - // TODO: Migrate to async - var admins = _userRepository.Get() + var admins = await _userRepository.Get() .Select(u => new User { Email = u.Email, Profile = u.Profile } ) .Where(u => u.Profile == Domain.Enums.Profile.Administrator) - .ToList(); + .ToListAsync(); InternetAddressList list = new InternetAddressList(); foreach (var admin in admins) @@ -150,7 +149,6 @@ public async Task TestAsync(string email, string name) public async Task> ProcessBounceMessagesAsync() { - // TODO: Improve async/await var log = new List(); if(string.IsNullOrEmpty(_settings.BounceFolder)) @@ -159,25 +157,25 @@ public async Task> ProcessBounceMessagesAsync() return log; } - _imapClient.Connect(_settings.HostName, _settings.ImapPort, true); - _imapClient.Authenticate(_settings.Username, _settings.Password); + await _imapClient.ConnectAsync(_settings.HostName, _settings.ImapPort, true); + await _imapClient.AuthenticateAsync(_settings.Username, _settings.Password); - var bounceFolder = GetBounceFolder(); + var bounceFolder = await GetBounceFolderAsync(); await bounceFolder.OpenAsync(FolderAccess.ReadWrite); var MAX_EMAILS_TO_PROCESS = 50; - var items = bounceFolder.Fetch(0, MAX_EMAILS_TO_PROCESS, MessageSummaryItems.UniqueId | MessageSummaryItems.Size | MessageSummaryItems.Flags); + var items = await bounceFolder.FetchAsync(0, MAX_EMAILS_TO_PROCESS, MessageSummaryItems.UniqueId | MessageSummaryItems.Size | MessageSummaryItems.Flags); foreach (var item in items) { - var message = bounceFolder.GetMessage(item.UniqueId); + var message = await bounceFolder.GetMessageAsync(item.UniqueId); var bounce = new MailBounce(message.Subject, message.TextBody); - bounceFolder.AddFlags(item.UniqueId, MessageFlags.Deleted, true); + await bounceFolder.AddFlagsAsync(item.UniqueId, MessageFlags.Deleted, true); if (bounce.IsBounce) { log.Add($"Email bounce processado: subject: {message.Subject}, errorCode: {bounce.ErrorCode}"); - _ctx.MailBounces.Add(bounce); + await _ctx.MailBounces.AddAsync(bounce); } else { @@ -186,20 +184,20 @@ public async Task> ProcessBounceMessagesAsync() } - _ctx.SaveChanges(); + await _ctx.SaveChangesAsync(); // Remove os emails bounce no server - bounceFolder.Expunge(); + await bounceFolder.ExpungeAsync(); - _imapClient.Disconnect(true); + await _imapClient.DisconnectAsync(true); return log; } - private IMailFolder? GetBounceFolder() + private async Task GetBounceFolderAsync() { - var personal = _imapClient.GetFolder(_imapClient.PersonalNamespaces[0]); - foreach (var folder in personal.GetSubfolders(false)) + var personal = await _imapClient.GetFolderAsync(_imapClient.PersonalNamespaces[0].Path); + foreach (var folder in await personal.GetSubfoldersAsync(false)) if (folder.Name == _settings.BounceFolder) return folder; @@ -216,10 +214,10 @@ public bool IsBounce(string email, IList bounces) var hardBounces = bounces.Where(b => !b.IsSoft).ToList(); var softBounces = bounces.Where(b => b.IsSoft && b.CreationDate > DateTime.Now.AddDays(-1)).ToList(); - if (hardBounces.Any(b => b.Email == email)) + if (hardBounces.Exists(b => b.Email == email)) return true; - if (softBounces.Any(b => b.Email == email)) + if (softBounces.Exists(b => b.Email == email)) return true; return false; From ee11839d87cc6aa35dcd47e1b445329a0fd9cf55 Mon Sep 17 00:00:00 2001 From: Henrique Holtz Date: Thu, 13 Jun 2024 07:24:31 -0300 Subject: [PATCH 25/37] perf: MuambatorService.AddPackageToTrackerAsync => Using async/await instead of "GetAwaiter().GetResult()" --- ShareBook/ShareBook.Service/Muambator/MuambatorService.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ShareBook/ShareBook.Service/Muambator/MuambatorService.cs b/ShareBook/ShareBook.Service/Muambator/MuambatorService.cs index 3849f3e4..f342ae0e 100644 --- a/ShareBook/ShareBook.Service/Muambator/MuambatorService.cs +++ b/ShareBook/ShareBook.Service/Muambator/MuambatorService.cs @@ -27,8 +27,8 @@ public async Task AddPackageToTrackerAsync(Book book, User winner, stri emails = new[] { emailWinner, emailDonor, emailFacilitator } }; - // TODO: GetAwaiter().GetResult() - string jsonResponse = url.WithHeader("Content-type", "application/json").PostJsonAsync(jsonRequest).ReceiveString().GetAwaiter().GetResult(); + + string jsonResponse = await url.WithHeader("Content-type", "application/json").PostJsonAsync(jsonRequest).ReceiveString(); result = JsonConvert.DeserializeObject(jsonResponse); } From e8cb7efd5b5ae1de2f925ec54d665f13c6ac4522 Mon Sep 17 00:00:00 2001 From: Henrique Holtz Date: Thu, 13 Jun 2024 07:35:46 -0300 Subject: [PATCH 26/37] perf: IUserService => Turning methods "ValidOldPasswordAndChangeUserPassword" and "ChangeUserPassword" as async and its usages --- .../ShareBook.Api/Controllers/AccountController.cs | 6 +++--- ShareBook/ShareBook.Service/User/IUserService.cs | 4 ++-- ShareBook/ShareBook.Service/User/UserService.cs | 12 ++++++------ 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/ShareBook/ShareBook.Api/Controllers/AccountController.cs b/ShareBook/ShareBook.Api/Controllers/AccountController.cs index 931d72e6..c8dee7eb 100644 --- a/ShareBook/ShareBook.Api/Controllers/AccountController.cs +++ b/ShareBook/ShareBook.Api/Controllers/AccountController.cs @@ -209,11 +209,11 @@ public async Task UpdateAsync([FromBody] UpdateUserVM updateUserV [Authorize("Bearer")] [HttpPut("ChangePassword")] - public Result ChangePassword([FromBody] ChangePasswordUserVM changePasswordUserVM) + public async Task> ChangePasswordAsync([FromBody] ChangePasswordUserVM changePasswordUserVM) { var user = new User() { Password = changePasswordUserVM.OldPassword }; user.Id = new Guid(Thread.CurrentPrincipal?.Identity?.Name); - return _userService.ValidOldPasswordAndChangeUserPassword(user, changePasswordUserVM.NewPassword); + return await _userService.ValidOldPasswordAndChangeUserPasswordAsync(user, changePasswordUserVM.NewPassword); } [HttpPut("ChangeUserPasswordByHashCode")] @@ -228,7 +228,7 @@ public async Task ChangeUserPasswordByHashCodeAsync([FromBody] Ch var user = await _userService.FindAsync((result.Value as User).Id); user.Password = newPassword; - var resultChangePasswordUser = _userService.ChangeUserPassword(user, newPassword); + var resultChangePasswordUser = await _userService.ChangeUserPasswordAsync(user, newPassword); if (!resultChangePasswordUser.Success) return BadRequest(resultChangePasswordUser); diff --git a/ShareBook/ShareBook.Service/User/IUserService.cs b/ShareBook/ShareBook.Service/User/IUserService.cs index b9a3db0f..2f84c37a 100644 --- a/ShareBook/ShareBook.Service/User/IUserService.cs +++ b/ShareBook/ShareBook.Service/User/IUserService.cs @@ -13,8 +13,8 @@ public interface IUserService : IBaseService Task> AuthenticationByEmailAndPasswordAsync(User user); bool IsValidPassword(User user, string decryptedPass); new Task> UpdateAsync(User user); - Result ValidOldPasswordAndChangeUserPassword(User user, string newPassword); - Result ChangeUserPassword(User user, string newPassword); + Task> ValidOldPasswordAndChangeUserPasswordAsync(User user, string newPassword); + Task> ChangeUserPasswordAsync(User user, string newPassword); Task GenerateHashCodePasswordAndSendEmailToUserAsync(string email); Task ConfirmHashCodePasswordAsync(string hashCodePassword); IList GetFacilitators(Guid userIdDonator); diff --git a/ShareBook/ShareBook.Service/User/UserService.cs b/ShareBook/ShareBook.Service/User/UserService.cs index 06a85a66..af52d35d 100644 --- a/ShareBook/ShareBook.Service/User/UserService.cs +++ b/ShareBook/ShareBook.Service/User/UserService.cs @@ -170,19 +170,19 @@ public override async Task FindAsync(object keyValue) return await _repository.FindAsync(includes, keyValue); } - public Result ValidOldPasswordAndChangeUserPassword(User user, string newPassword) + public async Task> ValidOldPasswordAndChangeUserPasswordAsync(User user, string newPassword) { var resultUserAuth = this.AuthenticationByIdAndPassword(user); if (resultUserAuth.Success) - ChangeUserPassword(resultUserAuth.Value, newPassword); + await ChangeUserPasswordAsync(resultUserAuth.Value, newPassword); return resultUserAuth; } - public Result ChangeUserPassword(User user, string newPassword) + public async Task> ChangeUserPasswordAsync(User user, string newPassword) { - var result = Validate(user); + var result = await ValidateAsync(user); // Senha forte não é mais obrigatória. Apenas validação de tamanho. if (newPassword.Length < 6 || newPassword.Length > 32) @@ -190,8 +190,7 @@ public Result ChangeUserPassword(User user, string newPassword) user.ChangePassword(newPassword); user = GetUserEncryptedPass(user); - // TODO: Remove "GetAwaiter().GetResult()" - user = _userRepository.UpdatePasswordAsync(user).GetAwaiter().GetResult(); + user = await _userRepository.UpdatePasswordAsync(user); result.Value = UserCleanup(user); return result; @@ -269,6 +268,7 @@ public IList GetAdmins() { private Result AuthenticationByIdAndPassword(User user) { + // TODO: Migrate to async var result = Validate(user, x => x.Id, x => x.Password); string decryptedPass = user.Password; From 003189cafbd9eff850c2c5cf8ac9b5d491d5cdb0 Mon Sep 17 00:00:00 2001 From: Henrique Holtz Date: Thu, 13 Jun 2024 07:53:58 -0300 Subject: [PATCH 27/37] perf: IBookService => Migrating 4 methods to async and its usages/endpoints --- .../Controllers/BookController.cs | 12 ++-- .../ShareBook.Service/Book/BookService.cs | 60 +++++++++---------- .../ShareBook.Service/Book/IBookService.cs | 8 +-- 3 files changed, 40 insertions(+), 40 deletions(-) diff --git a/ShareBook/ShareBook.Api/Controllers/BookController.cs b/ShareBook/ShareBook.Api/Controllers/BookController.cs index 6fa21ba1..1ef0affc 100644 --- a/ShareBook/ShareBook.Api/Controllers/BookController.cs +++ b/ShareBook/ShareBook.Api/Controllers/BookController.cs @@ -160,23 +160,23 @@ public async Task GetByIdAsync(string id) } [HttpGet("AvailableBooks")] - public IList AvailableBooks() + public async Task> AvailableBooksAsync() { - var books = _service.AvailableBooks(); + var books = await _service.AvailableBooksAsync(); return _mapper.Map>(books); } [HttpGet("Random15Books")] - public IList Random15Books() + public async Task> Random15BooksAsync() { - var books = _service.Random15Books(); + var books = await _service.Random15BooksAsync(); return _mapper.Map>(books); } [HttpGet("Random15EBooks")] - public IList Random15EBooks() + public async Task> Random15EBooksAsync() { - var books = _service.Random15EBooks(); + var books = await _service.Random15EBooksAsync(); return _mapper.Map>(books); } diff --git a/ShareBook/ShareBook.Service/Book/BookService.cs b/ShareBook/ShareBook.Service/Book/BookService.cs index 898c1349..6b52dc88 100644 --- a/ShareBook/ShareBook.Service/Book/BookService.cs +++ b/ShareBook/ShareBook.Service/Book/BookService.cs @@ -113,44 +113,44 @@ public IList FreightOptions() return enumValues; } - public IList AvailableBooks() + public async Task> AvailableBooksAsync() { return SetImageUrl( - _repository.Get() - .Include(b => b.User) - .ThenInclude(u => u.Address) - .Include(b => b.Category) - .Where(b => b.Status == BookStatus.Available) - .OrderByDescending(b => b.CreationDate) - .ToList() + await _repository.Get() + .Include(b => b.User) + .ThenInclude(u => u.Address) + .Include(b => b.Category) + .Where(b => b.Status == BookStatus.Available) + .OrderByDescending(b => b.CreationDate) + .ToListAsync() ); } - public IList Random15Books() + public async Task> Random15BooksAsync() { return SetImageUrl( - _repository.Get() - .Include(b => b.User) - .ThenInclude(u => u.Address) - .Include(b => b.Category) - .Where(b => b.Status == BookStatus.Available) - .OrderBy(x => Guid.NewGuid()) // ordem aleatória - .Take(15) // apenas 15 registros - .ToList() + await _repository.Get() + .Include(b => b.User) + .ThenInclude(u => u.Address) + .Include(b => b.Category) + .Where(b => b.Status == BookStatus.Available) + .OrderBy(x => Guid.NewGuid()) // ordem aleatória + .Take(15) // apenas 15 registros + .ToListAsync() ); } - public IList Random15EBooks() + public async Task> Random15EBooksAsync() { return SetImageUrl( - _repository.Get() - .Include(b => b.User) - .ThenInclude(u => u.Address) - .Include(b => b.Category) - .Where(b => b.Status == BookStatus.Available && b.Type == BookType.Eletronic) - .OrderBy(x => Guid.NewGuid()) // ordem aleatória - .Take(15) // apenas 15 registros - .ToList() + await _repository.Get() + .Include(b => b.User) + .ThenInclude(u => u.Address) + .Include(b => b.Category) + .Where(b => b.Status == BookStatus.Available && b.Type == BookType.Eletronic) + .OrderBy(x => Guid.NewGuid()) // ordem aleatória + .Take(15) // apenas 15 registros + .ToListAsync() ); } @@ -160,10 +160,10 @@ private IList SetImageUrl(IList books) } - public IList GetAll(int page, int items) - => _repository.Get().Include(b => b.User).Include(b => b.BookUsers) - .Skip((page - 1) * items) - .Take(items).ToList(); + public async Task> GetAllAsync(int page, int items) + => await _repository.Get().Include(b => b.User).Include(b => b.BookUsers) + .Skip((page - 1) * items) + .Take(items).ToListAsync(); public override async Task FindAsync(object keyValue) { diff --git a/ShareBook/ShareBook.Service/Book/IBookService.cs b/ShareBook/ShareBook.Service/Book/IBookService.cs index 13551432..e356e0f8 100644 --- a/ShareBook/ShareBook.Service/Book/IBookService.cs +++ b/ShareBook/ShareBook.Service/Book/IBookService.cs @@ -18,17 +18,17 @@ public interface IBookService : IBaseService IList FreightOptions(); - IList AvailableBooks(); + Task> AvailableBooksAsync(); - IList Random15Books(); + Task> Random15BooksAsync(); - IList Random15EBooks(); + Task> Random15EBooksAsync(); Task> FullSearchAsync(string criteria, int page, int itemsPerPage, bool isAdmin = false); Task> ByCategoryIdAsync(Guid categoryId, int page, int items); - IList GetAll(int page, int items); + Task> GetAllAsync(int page, int items); Task BySlugAsync(string slug); From 58cc6184322f29726759187b11023ff5ce01c7ff Mon Sep 17 00:00:00 2001 From: Henrique Holtz Date: Thu, 13 Jun 2024 07:57:02 -0300 Subject: [PATCH 28/37] perf: IBookService.GetBookWithAllUsersAsync => Using "FirstOrDefaultAsync" directly without getting the list and then FirstOrDefault --- ShareBook/ShareBook.Service/Book/BookService.cs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/ShareBook/ShareBook.Service/Book/BookService.cs b/ShareBook/ShareBook.Service/Book/BookService.cs index 6b52dc88..67d9f697 100644 --- a/ShareBook/ShareBook.Service/Book/BookService.cs +++ b/ShareBook/ShareBook.Service/Book/BookService.cs @@ -374,15 +374,12 @@ public async Task AddFacilitatorNotesAsync(Guid bookId, string facilitatorNotes) public async Task GetBookWithAllUsersAsync(Guid bookId) { - // TODO: Verify if we can use FirstOrDefault/FirstOrDefaultAsync directly without using the "ToListAsync" - var books = await _repository + return await _repository .Get().Include(x => x.User).ThenInclude(u => u.Address) .Include(x => x.UserFacilitator).ThenInclude(u => u.Address) .Include(x => x.BookUsers).ThenInclude(bu => bu.User).ThenInclude(u => u.Address) .Where(x => x.Id == bookId) - .ToListAsync(); - - return books.FirstOrDefault(); + .FirstOrDefaultAsync(); } public async Task RenewChooseDateAsync(Guid bookId) From ca163a46dcbd947ed17791cf05de94cdcd2708a3 Mon Sep 17 00:00:00 2001 From: Henrique Holtz Date: Thu, 13 Jun 2024 08:01:19 -0300 Subject: [PATCH 29/37] perf: BookUserEmailService => Got rid the latest ".Wait()" usages --- .../BookUser/BookUserEmailService.cs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/ShareBook/ShareBook.Service/BookUser/BookUserEmailService.cs b/ShareBook/ShareBook.Service/BookUser/BookUserEmailService.cs index 10109c65..74a1bbf8 100644 --- a/ShareBook/ShareBook.Service/BookUser/BookUserEmailService.cs +++ b/ShareBook/ShareBook.Service/BookUser/BookUserEmailService.cs @@ -215,10 +215,11 @@ public async Task SendEmailDonationDeclinedAsync(Book book, BookUser bookUserWin var html = await _emailTemplate.GenerateHtmlFromTemplateAsync(BookNoticeDeclinedUsersTemplate, vm); var emailSubject = $"Resultado da doação do livro {book.Title}."; - bookUsersDeclined.ForEach(bookUser => + bookUsersDeclined.ForEach(async (bookUser) => { + // TODO: Find out a better approach instead of awaiting one by one if (bookUser.User.AllowSendingEmail) - _emailService.SendAsync(bookUser.User.Email, bookUser.User.Name, html, emailSubject).Wait(); + await _emailService.SendAsync(bookUser.User.Email, bookUser.User.Name, html, emailSubject); }); } @@ -228,10 +229,11 @@ public async Task SendEmailDonationCanceledAsync(Book book, List bookU var vm = new { book }; var html = await _emailTemplate.GenerateHtmlFromTemplateAsync(BookCanceledNoticeUsersTemplate, vm); - bookUsers.ForEach(bookUser => + bookUsers.ForEach(async (bookUser) => { + // TODO: Find out a better approach instead of awaiting one by one if (bookUser.User.AllowSendingEmail) - _emailService.SendAsync(bookUser.User.Email, bookUser.User.Name, html, $"Resultado da doação do livro {book.Title}.").Wait(); + await _emailService.SendAsync(bookUser.User.Email, bookUser.User.Name, html, $"Resultado da doação do livro {book.Title}."); }); } @@ -249,7 +251,7 @@ public async Task SendEmailBookCanceledToAdminsAndDonorAsync(BookCancelationDTO }; var html = await _emailTemplate.GenerateHtmlFromTemplateAsync(BookCanceledTemplate, templateData); - _emailService.SendAsync(donor.Email, donor.Name, html, BookCanceledTitle, copyAdmins: true, highPriority: true).Wait(); + await _emailService.SendAsync(donor.Email, donor.Name, html, BookCanceledTitle, copyAdmins: true, highPriority: true); } public async Task SendEmailTrackingNumberInformedAsync(BookUser bookUserWinner, Book book) From b03f467bf742448e3eb940d6e3a9ee64b41ec4a9 Mon Sep 17 00:00:00 2001 From: Henrique Holtz Date: Thu, 13 Jun 2024 08:05:38 -0300 Subject: [PATCH 30/37] perf: IPushNotificationService => Turning all 3 methods as async --- .../BookUser/BookUserEmailService.cs | 4 ++-- .../PushNotification/IPushNotificationService.cs | 7 ++++--- .../PushNotification/PushNotificationService.cs | 13 +++++++------ 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/ShareBook/ShareBook.Service/BookUser/BookUserEmailService.cs b/ShareBook/ShareBook.Service/BookUser/BookUserEmailService.cs index 74a1bbf8..2579cc53 100644 --- a/ShareBook/ShareBook.Service/BookUser/BookUserEmailService.cs +++ b/ShareBook/ShareBook.Service/BookUser/BookUserEmailService.cs @@ -104,7 +104,7 @@ public async Task SendEmailBookDonorAsync(BookUser bookUser, Book bookRequested) }; // push notification - _notificationService.SendNotificationByEmail( + await _notificationService.SendNotificationByEmailAsync( bookRequested.User.Email, $"Seu livro foi solicitado", $" O Interessado é {vm.RequestingUser.NickName}" ); @@ -173,7 +173,7 @@ public async Task SendEmailBookInterestedAsync(BookUser bookUser, Book book) }; // push notification - _notificationService.SendNotificationByEmail(bookUser.User.Email, $"Você solicitou o livro {vm.NameBook}", $"Aguarde até o dia {vm.ChooseDate} que será anunciado o ganhador. Boa sorte!"); + await _notificationService.SendNotificationByEmailAsync(bookUser.User.Email, $"Você solicitou o livro {vm.NameBook}", $"Aguarde até o dia {vm.ChooseDate} que será anunciado o ganhador. Boa sorte!"); var html = await _emailTemplate.GenerateHtmlFromTemplateAsync(BookNoticeInterestedTemplate, vm); await _emailService.SendAsync(bookUser.User.Email, bookUser.User.Name, html, BookNoticeInterestedTitle); diff --git a/ShareBook/ShareBook.Service/PushNotification/IPushNotificationService.cs b/ShareBook/ShareBook.Service/PushNotification/IPushNotificationService.cs index fa0e231e..8ccde71e 100644 --- a/ShareBook/ShareBook.Service/PushNotification/IPushNotificationService.cs +++ b/ShareBook/ShareBook.Service/PushNotification/IPushNotificationService.cs @@ -1,11 +1,12 @@ using ShareBook.Domain; +using System.Threading.Tasks; namespace ShareBook.Service.Notification { public interface IPushNotificationService { - string SendNotificationSegments(NotificationOnesignal notficationSettings); - string SendNotificationByKey(NotificationOnesignal notficationSettings); - string SendNotificationByEmail(string email, string title, string content); + Task SendNotificationSegmentsAsync(NotificationOnesignal notficationSettings); + Task SendNotificationByKeyAsync(NotificationOnesignal notficationSettings); + Task SendNotificationByEmailAsync(string email, string title, string content); } } diff --git a/ShareBook/ShareBook.Service/PushNotification/PushNotificationService.cs b/ShareBook/ShareBook.Service/PushNotification/PushNotificationService.cs index 1d9cc0e4..e74fc3e2 100644 --- a/ShareBook/ShareBook.Service/PushNotification/PushNotificationService.cs +++ b/ShareBook/ShareBook.Service/PushNotification/PushNotificationService.cs @@ -7,6 +7,7 @@ using ShareBook.Domain.Enums; using System; using System.Collections.Generic; +using System.Threading.Tasks; namespace ShareBook.Service.Notification; @@ -20,7 +21,7 @@ public PushNotificationService(IOptions pushNotificati _oneSignalClient = new OneSignalClient(_settings.ApiKey); } - public string SendNotificationSegments(NotificationOnesignal onesignal) + public async Task SendNotificationSegmentsAsync(NotificationOnesignal onesignal) { if (!_settings.IsActive) return ""; @@ -37,12 +38,12 @@ public string SendNotificationSegments(NotificationOnesignal onesignal) notificationCreateOptions.Headings.Add(LanguageCodes.Portuguese, onesignal.Title); notificationCreateOptions.Contents.Add(LanguageCodes.Portuguese, onesignal.Content); - _oneSignalClient.Notifications.Create(notificationCreateOptions); + await _oneSignalClient.Notifications.CreateAsync(notificationCreateOptions); return "Enviado com sucesso"; } - public string SendNotificationByKey(NotificationOnesignal onesignal) + public async Task SendNotificationByKeyAsync(NotificationOnesignal onesignal) { if (!_settings.IsActive) return ""; @@ -62,13 +63,13 @@ public string SendNotificationByKey(NotificationOnesignal onesignal) notificationCreateOptions.Headings.Add(LanguageCodes.Portuguese, onesignal.Title); notificationCreateOptions.Contents.Add(LanguageCodes.Portuguese, onesignal.Content); - _oneSignalClient.Notifications.Create(notificationCreateOptions); + await _oneSignalClient.Notifications.CreateAsync(notificationCreateOptions); return $"Notification enviado para o {onesignal.Value} com sucesso"; } - public string SendNotificationByEmail(string email, string title, string content) + public async Task SendNotificationByEmailAsync(string email, string title, string content) { if (!_settings.IsActive) return ""; @@ -89,7 +90,7 @@ public string SendNotificationByEmail(string email, string title, string content notificationCreateOptions.Headings.Add(LanguageCodes.Portuguese, title); notificationCreateOptions.Contents.Add(LanguageCodes.Portuguese, content); - _oneSignalClient.Notifications.Create(notificationCreateOptions); + await _oneSignalClient.Notifications.CreateAsync(notificationCreateOptions); return $"Notification enviado para o {email} com sucesso"; } From 7184ba147861548865313303ba207fbe25a0ae5e Mon Sep 17 00:00:00 2001 From: Henrique Holtz Date: Fri, 14 Jun 2024 06:55:58 -0300 Subject: [PATCH 31/37] test: Adding unit test for "Jobs.CancelAbandonedDonations" --- .../Jobs/CancelAbandonedDonationsTests.cs | 61 +++++++++++++++++++ .../Jobs/0 - CancelAbandonedDonations.cs | 2 +- 2 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 ShareBook/ShareBook.Test.Unit/Jobs/CancelAbandonedDonationsTests.cs diff --git a/ShareBook/ShareBook.Test.Unit/Jobs/CancelAbandonedDonationsTests.cs b/ShareBook/ShareBook.Test.Unit/Jobs/CancelAbandonedDonationsTests.cs new file mode 100644 index 00000000..d5343f6f --- /dev/null +++ b/ShareBook/ShareBook.Test.Unit/Jobs/CancelAbandonedDonationsTests.cs @@ -0,0 +1,61 @@ +using Moq; +using Sharebook.Jobs; +using ShareBook.Service; +using System.Threading.Tasks; +using Xunit; +using ShareBook.Repository; +using Microsoft.Extensions.Configuration; +using System.Collections.Generic; +using ShareBook.Domain; +using ShareBook.Domain.DTOs; +using ShareBook.Test.Unit.Mocks; +using ShareBook.Domain.Common; +using System.Linq; +using System; + +namespace ShareBook.Test.Unit.Jobs +{ + public class CancelAbandonedDonationsTests + { + private readonly Mock _mockJobHistoryRepository = new(); + private readonly Mock _mockBookService = new(); + private readonly Mock _mockBookUserService = new(); + private readonly Mock _mockConfiguration = new(); + + public CancelAbandonedDonationsTests() + { + // Mocking 4 books. 2 Of them are ready to be cancelled. + int maxLateDonationDaysAutoCancel = 90; + List allBooks = new List { + BookMock.GetLordTheRings(), + BookMock.GetLordTheRings(), + BookMock.GetLordTheRings(), + BookMock.GetLordTheRings(), + }; + var booksToCancel = allBooks.Take(2); + foreach (var book in booksToCancel) + book.ChooseDate = DateTime.Now.AddDays((maxLateDonationDaysAutoCancel + 2) * -1); + + _mockConfiguration.SetupGet(s => s[It.IsAny()]).Returns(maxLateDonationDaysAutoCancel.ToString()); + _mockBookService.Setup(s => s.GetBooksChooseDateIsLateAsync()).ReturnsAsync(allBooks); + _mockBookUserService.Setup(s => s.CancelAsync(It.IsAny())).ReturnsAsync(() => new Result(BookMock.GetLordTheRings())); + } + + [Fact] + public async Task Cancelling2Of4AbandonedBooks() + { + CancelAbandonedDonations job = new CancelAbandonedDonations(_mockJobHistoryRepository.Object, _mockBookService.Object, _mockBookUserService.Object, _mockConfiguration.Object); + + JobHistory result = await job.WorkAsync(); + + Assert.True(result.IsSuccess); + Assert.Equal("Encontradas 2 doações abandonadas com mais de 90 dias de atraso.\n\nDoação do livro Lord of the Rings foi cancelada.\nDoação do livro Lord of the Rings foi cancelada.\n", result.Details); + Assert.Equal(CancelAbandonedDonations.JobName, result.JobName); + + _mockBookService.Verify(c => c.GetBooksChooseDateIsLateAsync(), Times.Once); + _mockBookUserService.Verify(c => c.CancelAsync(It.IsAny()), Times.Exactly(2)); + _mockBookService.VerifyNoOtherCalls(); + _mockBookUserService.VerifyNoOtherCalls(); + } + } +} diff --git a/ShareBook/Sharebook.Jobs/Jobs/0 - CancelAbandonedDonations.cs b/ShareBook/Sharebook.Jobs/Jobs/0 - CancelAbandonedDonations.cs index 4a285a6f..3b32b10c 100644 --- a/ShareBook/Sharebook.Jobs/Jobs/0 - CancelAbandonedDonations.cs +++ b/ShareBook/Sharebook.Jobs/Jobs/0 - CancelAbandonedDonations.cs @@ -16,10 +16,10 @@ public class CancelAbandonedDonations : GenericJob, IJob private readonly IBookUserService _bookUserService; private readonly int _maxLateDonationDaysAutoCancel; private readonly IConfiguration _configuration; + public new const string JobName = "CancelAbandonedDonations"; public CancelAbandonedDonations(IJobHistoryRepository jobHistoryRepo, IBookService bookService, IBookUserService bookUserService, IConfiguration configuration) : base(jobHistoryRepo) { - JobName = "CancelAbandonedDonations"; Description = "Cancela as doações abandonadas."; Interval = Interval.Dayly; Active = true; From b6e9ac0085c03b2512df939d85aa5c8c46d4439d Mon Sep 17 00:00:00 2001 From: Henrique Holtz Date: Fri, 14 Jun 2024 07:40:38 -0300 Subject: [PATCH 32/37] test: Jobs.CancelAbandonedDonations => Adding unit test to make sure is not cancelling books which are not to be cancelled --- ...s => 0 - CancelAbandonedDonationsTests.cs} | 43 +++++++++++++------ ...earchTests.cs => 4 - MeetupSearchTests.cs} | 0 .../ShareBook.Test.Unit.csproj | 3 +- 3 files changed, 33 insertions(+), 13 deletions(-) rename ShareBook/ShareBook.Test.Unit/Jobs/{CancelAbandonedDonationsTests.cs => 0 - CancelAbandonedDonationsTests.cs} (64%) rename ShareBook/ShareBook.Test.Unit/Jobs/{MeetupSearchTests.cs => 4 - MeetupSearchTests.cs} (100%) diff --git a/ShareBook/ShareBook.Test.Unit/Jobs/CancelAbandonedDonationsTests.cs b/ShareBook/ShareBook.Test.Unit/Jobs/0 - CancelAbandonedDonationsTests.cs similarity index 64% rename from ShareBook/ShareBook.Test.Unit/Jobs/CancelAbandonedDonationsTests.cs rename to ShareBook/ShareBook.Test.Unit/Jobs/0 - CancelAbandonedDonationsTests.cs index d5343f6f..891a770a 100644 --- a/ShareBook/ShareBook.Test.Unit/Jobs/CancelAbandonedDonationsTests.cs +++ b/ShareBook/ShareBook.Test.Unit/Jobs/0 - CancelAbandonedDonationsTests.cs @@ -12,6 +12,7 @@ using ShareBook.Domain.Common; using System.Linq; using System; +using Xunit.Extensions.Ordering; namespace ShareBook.Test.Unit.Jobs { @@ -21,29 +22,47 @@ public class CancelAbandonedDonationsTests private readonly Mock _mockBookService = new(); private readonly Mock _mockBookUserService = new(); private readonly Mock _mockConfiguration = new(); - - public CancelAbandonedDonationsTests() - { - // Mocking 4 books. 2 Of them are ready to be cancelled. - int maxLateDonationDaysAutoCancel = 90; - List allBooks = new List { + private static int _maxLateDonationDaysAutoCancel = 90; + private static List _allBooks = new List { BookMock.GetLordTheRings(), BookMock.GetLordTheRings(), BookMock.GetLordTheRings(), BookMock.GetLordTheRings(), }; - var booksToCancel = allBooks.Take(2); - foreach (var book in booksToCancel) - book.ChooseDate = DateTime.Now.AddDays((maxLateDonationDaysAutoCancel + 2) * -1); - _mockConfiguration.SetupGet(s => s[It.IsAny()]).Returns(maxLateDonationDaysAutoCancel.ToString()); - _mockBookService.Setup(s => s.GetBooksChooseDateIsLateAsync()).ReturnsAsync(allBooks); + public CancelAbandonedDonationsTests() + { + + _mockConfiguration.SetupGet(s => s[It.IsAny()]).Returns(_maxLateDonationDaysAutoCancel.ToString()); + _mockBookService.Setup(s => s.GetBooksChooseDateIsLateAsync()).ReturnsAsync(_allBooks); _mockBookUserService.Setup(s => s.CancelAsync(It.IsAny())).ReturnsAsync(() => new Result(BookMock.GetLordTheRings())); } - [Fact] + [Fact, Order(1)] + public async Task NotCancellingAnyBook() + { + CancelAbandonedDonations job = new CancelAbandonedDonations(_mockJobHistoryRepository.Object, _mockBookService.Object, _mockBookUserService.Object, _mockConfiguration.Object); + + JobHistory result = await job.WorkAsync(); + + Assert.True(result.IsSuccess); + Assert.Equal("Encontradas 0 doações abandonadas com mais de 90 dias de atraso.\n\n", result.Details); + Assert.Equal(CancelAbandonedDonations.JobName, result.JobName); + + _mockBookService.Verify(c => c.GetBooksChooseDateIsLateAsync(), Times.Once); + _mockBookUserService.Verify(c => c.CancelAsync(It.IsAny()), Times.Never); + _mockBookService.VerifyNoOtherCalls(); + _mockBookUserService.VerifyNoOtherCalls(); + } + + [Fact, Order(2)] public async Task Cancelling2Of4AbandonedBooks() { + // Mocking 4 books. 2 Of them are ready to be cancelled. + var booksToCancel = _allBooks.Take(2); + foreach (var book in booksToCancel) + book.ChooseDate = DateTime.Now.AddDays((_maxLateDonationDaysAutoCancel + 2) * -1); + CancelAbandonedDonations job = new CancelAbandonedDonations(_mockJobHistoryRepository.Object, _mockBookService.Object, _mockBookUserService.Object, _mockConfiguration.Object); JobHistory result = await job.WorkAsync(); diff --git a/ShareBook/ShareBook.Test.Unit/Jobs/MeetupSearchTests.cs b/ShareBook/ShareBook.Test.Unit/Jobs/4 - MeetupSearchTests.cs similarity index 100% rename from ShareBook/ShareBook.Test.Unit/Jobs/MeetupSearchTests.cs rename to ShareBook/ShareBook.Test.Unit/Jobs/4 - MeetupSearchTests.cs diff --git a/ShareBook/ShareBook.Test.Unit/ShareBook.Test.Unit.csproj b/ShareBook/ShareBook.Test.Unit/ShareBook.Test.Unit.csproj index 415389ce..28f5fa37 100644 --- a/ShareBook/ShareBook.Test.Unit/ShareBook.Test.Unit.csproj +++ b/ShareBook/ShareBook.Test.Unit/ShareBook.Test.Unit.csproj @@ -1,4 +1,4 @@ - + net8.0 @@ -11,6 +11,7 @@ + all runtime; build; native; contentfiles; analyzers; buildtransitive From c03f28d67cea74d1e16166f42e480b0ae8d4fba3 Mon Sep 17 00:00:00 2001 From: Henrique Holtz Date: Fri, 14 Jun 2024 08:22:36 -0300 Subject: [PATCH 33/37] test: Adding unit test for "Jobs.ChooseDateReminder" --- .../Jobs/1 - ChooseDateReminderTests.cs | 56 +++++++++++++++++++ .../ShareBook.Test.Unit/Mocks/BookMock.cs | 7 ++- .../Jobs/1 - ChooseDateReminder.cs | 7 +-- 3 files changed, 64 insertions(+), 6 deletions(-) create mode 100644 ShareBook/ShareBook.Test.Unit/Jobs/1 - ChooseDateReminderTests.cs diff --git a/ShareBook/ShareBook.Test.Unit/Jobs/1 - ChooseDateReminderTests.cs b/ShareBook/ShareBook.Test.Unit/Jobs/1 - ChooseDateReminderTests.cs new file mode 100644 index 00000000..74574bb9 --- /dev/null +++ b/ShareBook/ShareBook.Test.Unit/Jobs/1 - ChooseDateReminderTests.cs @@ -0,0 +1,56 @@ +using Moq; +using Sharebook.Jobs; +using ShareBook.Service; +using System.Threading.Tasks; +using Xunit; +using ShareBook.Repository; +using Microsoft.Extensions.Configuration; +using System.Collections.Generic; +using ShareBook.Domain; +using ShareBook.Domain.DTOs; +using ShareBook.Test.Unit.Mocks; +using ShareBook.Domain.Common; +using System.Linq; +using System; +using Xunit.Extensions.Ordering; + +namespace ShareBook.Test.Unit.Jobs +{ + public class ChooseDateReminderTests + { + private readonly Mock _mockJobHistoryRepository = new(); + private readonly Mock _mockBookService = new(); + private readonly Mock _mockEmailService = new(); + private readonly Mock _mockEmailTemplate = new(); + private const string HtmlMock = "Example"; + private static User _user = new User { Id = Guid.NewGuid(), Name = "TestUser", Email = "testuser@example.com" }; + private static Book _book = BookMock.GetLordTheRings(_user, _user); + private static List _allBooks = new List { _book }; + + public ChooseDateReminderTests() + { + _mockBookService.Setup(s => s.GetBooksChooseDateIsTodayAsync()).ReturnsAsync(_allBooks); + _mockEmailTemplate.Setup(s => s.GenerateHtmlFromTemplateAsync(It.IsAny(), It.IsAny())).ReturnsAsync(HtmlMock); + } + + [Fact] + public async Task SendReminderToTheUser() + { + ChooseDateReminder job = new ChooseDateReminder(_mockJobHistoryRepository.Object, _mockBookService.Object, _mockEmailService.Object, _mockEmailTemplate.Object); + + JobHistory result = await job.WorkAsync(); + + Assert.True(result.IsSuccess); + Assert.Equal("Lembrete amigável enviado para 'TestUser' referente ao livro 'Lord of the Rings'.", result.Details); + Assert.Equal(ChooseDateReminder.JobName, result.JobName); + + _mockBookService.Verify(c => c.GetBooksChooseDateIsTodayAsync(), Times.Once); + _mockEmailTemplate.Verify(c => c.GenerateHtmlFromTemplateAsync(It.Is(v => v.Equals("ChooseDateReminderTemplate")), It.IsAny()), Times.Once); + _mockEmailService.Verify(c => c.SendAsync(It.Is(v => v.Equals(_user.Email)), It.Is(v => v.Equals(_user.Name)), It.Is(v => v.Equals(HtmlMock)), It.Is(v => v.Equals(ChooseDateReminder.EmailSubject)), It.Is((v) => !v), It.Is((v) => v)), Times.Once); + + _mockBookService.VerifyNoOtherCalls(); + _mockEmailService.VerifyNoOtherCalls(); + _mockEmailTemplate.VerifyNoOtherCalls(); + } + } +} diff --git a/ShareBook/ShareBook.Test.Unit/Mocks/BookMock.cs b/ShareBook/ShareBook.Test.Unit/Mocks/BookMock.cs index c1d44642..f5cce228 100644 --- a/ShareBook/ShareBook.Test.Unit/Mocks/BookMock.cs +++ b/ShareBook/ShareBook.Test.Unit/Mocks/BookMock.cs @@ -7,16 +7,19 @@ namespace ShareBook.Test.Unit.Mocks { public class BookMock { - public static Book GetLordTheRings(User user) + public static Book GetLordTheRings(User user, User userFacilitator = null) { + Guid bookId = new Guid("d9f5fde8-ee7c-4cf5-aa90-35eca3c170b9"); return new Book() { - Id = new Guid("d9f5fde8-ee7c-4cf5-aa90-35eca3c170b9"), + Id = bookId, Title = "Lord of the Rings", Author = "J. R. R. Tolkien", ImageSlug = "lotr.png", ImageBytes = Encoding.UTF8.GetBytes("STRINGBASE64"), User = user, + BookUsers = new List { new BookUser { BookId = bookId, User = user } }, + UserFacilitator = userFacilitator, CategoryId = Guid.NewGuid(), Status = ShareBook.Domain.Enums.BookStatus.Available }; diff --git a/ShareBook/Sharebook.Jobs/Jobs/1 - ChooseDateReminder.cs b/ShareBook/Sharebook.Jobs/Jobs/1 - ChooseDateReminder.cs index 50b156e7..126a1939 100644 --- a/ShareBook/Sharebook.Jobs/Jobs/1 - ChooseDateReminder.cs +++ b/ShareBook/Sharebook.Jobs/Jobs/1 - ChooseDateReminder.cs @@ -13,6 +13,8 @@ public class ChooseDateReminder : GenericJob, IJob private readonly IEmailService _emailService; private readonly IEmailTemplate _emailTemplate; private readonly IBookService _bookService; + public new const string JobName = "ChooseDateReminder"; + public const string EmailSubject = "Hoje é o dia de escolher o ganhador!"; public ChooseDateReminder( IJobHistoryRepository jobHistoryRepo, @@ -21,7 +23,6 @@ public ChooseDateReminder( IEmailTemplate emailTemplate ) : base(jobHistoryRepo) { - JobName = "ChooseDateReminder"; Description = "Notifica o doador, com um lembrete amigável, no dia da doação. " + "Com cópia para o facilitador."; Interval = Interval.Dayly; @@ -67,8 +68,6 @@ public override async Task WorkAsync() private async Task SendEmailAsync(Book book) { - var emailSubject = "Hoje é o dia de escolher o ganhador!"; - var vm = new { DonorName = book.User.Name, @@ -80,7 +79,7 @@ private async Task SendEmailAsync(Book book) }; var emailBodyHTML = await _emailTemplate.GenerateHtmlFromTemplateAsync("ChooseDateReminderTemplate", vm); - await _emailService.SendAsync(book.User.Email, book.User.Name, emailBodyHTML, emailSubject, copyAdmins: false, highPriority: true); + await _emailService.SendAsync(book.User.Email, book.User.Name, emailBodyHTML, EmailSubject, copyAdmins: false, highPriority: true); } #endregion From e151a18c8e0630a0d7cc59f2616cc9050118d8c9 Mon Sep 17 00:00:00 2001 From: Henrique Holtz Date: Sat, 15 Jun 2024 06:41:43 -0300 Subject: [PATCH 34/37] test: Adding 3 unit tests for "Jobs.LateDonationNotification" --- .../Jobs/2 - LateDonationNotificationTests.cs | 121 ++++++++++++++++++ .../Jobs/2 - LateDonationNotification.cs | 26 ++-- 2 files changed, 133 insertions(+), 14 deletions(-) create mode 100644 ShareBook/ShareBook.Test.Unit/Jobs/2 - LateDonationNotificationTests.cs diff --git a/ShareBook/ShareBook.Test.Unit/Jobs/2 - LateDonationNotificationTests.cs b/ShareBook/ShareBook.Test.Unit/Jobs/2 - LateDonationNotificationTests.cs new file mode 100644 index 00000000..b55b72a8 --- /dev/null +++ b/ShareBook/ShareBook.Test.Unit/Jobs/2 - LateDonationNotificationTests.cs @@ -0,0 +1,121 @@ +using Moq; +using Sharebook.Jobs; +using ShareBook.Service; +using System.Threading.Tasks; +using Xunit; +using ShareBook.Repository; +using Microsoft.Extensions.Configuration; +using System.Collections.Generic; +using ShareBook.Domain; +using ShareBook.Domain.DTOs; +using ShareBook.Test.Unit.Mocks; +using System; +using Xunit.Extensions.Ordering; +using ShareBook.Domain.Enums; + +namespace ShareBook.Test.Unit.Jobs +{ + public class LateDonationNotificationTests + { + private readonly Mock _mockJobHistoryRepository = new(); + private readonly Mock _mockBookService = new(); + private readonly Mock _mockEmailService = new(); + private readonly Mock _mockEmailTemplate = new(); + private readonly Mock _mockConfiguration = new(); + private static int _maxLateDonationDays = 90; + private const string HtmlMock = "Example"; + private static User _softUser = new User { Id = Guid.NewGuid(), Name = "SoftUser", Email = "softuser@example.com" }; + private static User _hardUser = new User { Id = Guid.NewGuid(), Name = "HardUser", Email = "harduser@example.com" }; + private static Book _softBook = BookMock.GetLordTheRings(_softUser, _softUser); + private static Book _hardBook = BookMock.GetLordTheRings(_hardUser, _hardUser); + //private static List _allBooks = new List { _book1 }; + + public LateDonationNotificationTests() + { + _hardBook.ChooseDate = DateTime.Now.AddDays((_maxLateDonationDays + 2) * -1); + _hardBook.Status = BookStatus.AwaitingDonorDecision; + _hardUser.BooksDonated = new List { _hardBook }; + _mockConfiguration.SetupGet(s => s[It.IsAny()]).Returns(_maxLateDonationDays.ToString()); + _mockBookService.Setup(s => s.GetStatsAsync()).ReturnsAsync(new BookStatsDTO { TotalLate = 1, TotalOk = 10 }); + _mockEmailTemplate.Setup(s => s.GenerateHtmlFromTemplateAsync(It.IsAny(), It.IsAny())).ReturnsAsync(HtmlMock); + } + + [Fact, Order(1)] + public async Task SendSoftEmailToTheUserAndToAdmins_1BookLate() + { + _mockBookService.Setup(s => s.GetBooksChooseDateIsLateAsync()).ReturnsAsync(new List { _softBook }); + LateDonationNotification job = new LateDonationNotification(_mockJobHistoryRepository.Object, _mockBookService.Object, _mockEmailService.Object, _mockEmailTemplate.Object, _mockConfiguration.Object); + + JobHistory result = await job.WorkAsync(); + + Assert.True(result.IsSuccess); + Assert.Equal($"Encontradas 1 doações em atraso de 1 doadores distintos.E-mail enviado para o usuário: {_softUser.Name}", result.Details); + Assert.Equal(LateDonationNotification.JobName, result.JobName); + + _mockConfiguration.Verify(c => c[LateDonationNotification.ConfigMaxLateDonationDaysKey], Times.Once); + _mockEmailTemplate.Verify(c => c.GenerateHtmlFromTemplateAsync(It.Is(v => v.Equals(LateDonationNotification.EmailTemplateName)), It.IsAny()), Times.Once); + + _mockBookService.Verify(c => c.GetBooksChooseDateIsLateAsync(), Times.Once); + _mockBookService.Verify(c => c.GetStatsAsync(), Times.Once); + + _mockEmailService.Verify(c => c.SendToAdminsAsync(HtmlMock, LateDonationNotification.EmailAdminsSubject), Times.Once); + _mockEmailService.Verify(c => c.SendAsync(_softUser.Email, _softUser.Name, It.IsAny(), LateDonationNotification.EmailDonatorSoftSubject, false, true), Times.Once); + + + _mockConfiguration.VerifyNoOtherCalls(); + _mockEmailTemplate.VerifyNoOtherCalls(); + _mockBookService.VerifyNoOtherCalls(); + _mockEmailService.VerifyNoOtherCalls(); + } + + [Fact, Order(2)] + public async Task SendHardEmailToTheUserAndToAdmins_1BookLate() + { + _mockBookService.Setup(s => s.GetBooksChooseDateIsLateAsync()).ReturnsAsync(new List { _hardBook }); + LateDonationNotification job = new LateDonationNotification(_mockJobHistoryRepository.Object, _mockBookService.Object, _mockEmailService.Object, _mockEmailTemplate.Object, _mockConfiguration.Object); + + JobHistory result = await job.WorkAsync(); + + Assert.True(result.IsSuccess); + Assert.Equal($"Encontradas 1 doações em atraso de 1 doadores distintos.E-mail enviado para o usuário: {_hardUser.Name}", result.Details); + Assert.Equal(LateDonationNotification.JobName, result.JobName); + + _mockConfiguration.Verify(c => c[LateDonationNotification.ConfigMaxLateDonationDaysKey], Times.Once); + _mockEmailTemplate.Verify(c => c.GenerateHtmlFromTemplateAsync(It.Is(v => v.Equals(LateDonationNotification.EmailTemplateName)), It.IsAny()), Times.Once); + + _mockBookService.Verify(c => c.GetBooksChooseDateIsLateAsync(), Times.Once); + _mockBookService.Verify(c => c.GetStatsAsync(), Times.Once); + + _mockEmailService.Verify(c => c.SendToAdminsAsync(HtmlMock, LateDonationNotification.EmailAdminsSubject), Times.Once); + _mockEmailService.Verify(c => c.SendAsync(_hardUser.Email, _hardUser.Name, It.IsAny(), LateDonationNotification.EmailDonatorHardSubject, true, true), Times.Once); + + + _mockConfiguration.VerifyNoOtherCalls(); + _mockEmailTemplate.VerifyNoOtherCalls(); + _mockBookService.VerifyNoOtherCalls(); + _mockEmailService.VerifyNoOtherCalls(); + } + + [Fact, Order(3)] + public async Task NotSendAnyEmail_0BooksLate() + { + _mockBookService.Setup(s => s.GetBooksChooseDateIsLateAsync()).ReturnsAsync(new List()); + LateDonationNotification job = new LateDonationNotification(_mockJobHistoryRepository.Object, _mockBookService.Object, _mockEmailService.Object, _mockEmailTemplate.Object, _mockConfiguration.Object); + + JobHistory result = await job.WorkAsync(); + + Assert.True(result.IsSuccess); + Assert.Equal("Encontradas 0 doações em atraso de 0 doadores distintos.", result.Details); + Assert.Equal(LateDonationNotification.JobName, result.JobName); + + _mockConfiguration.Verify(c => c[LateDonationNotification.ConfigMaxLateDonationDaysKey], Times.Once); + _mockBookService.Verify(c => c.GetBooksChooseDateIsLateAsync(), Times.Once); + _mockBookService.Verify(c => c.GetStatsAsync(), Times.Once); + + _mockConfiguration.VerifyNoOtherCalls(); + _mockEmailTemplate.VerifyNoOtherCalls(); + _mockBookService.VerifyNoOtherCalls(); + _mockEmailService.VerifyNoOtherCalls(); + } + } +} diff --git a/ShareBook/Sharebook.Jobs/Jobs/2 - LateDonationNotification.cs b/ShareBook/Sharebook.Jobs/Jobs/2 - LateDonationNotification.cs index ddf352bf..9ee1c637 100644 --- a/ShareBook/Sharebook.Jobs/Jobs/2 - LateDonationNotification.cs +++ b/ShareBook/Sharebook.Jobs/Jobs/2 - LateDonationNotification.cs @@ -16,9 +16,14 @@ public class LateDonationNotification : GenericJob, IJob private readonly IEmailService _emailService; private readonly IEmailTemplate _emailTemplate; private readonly IBookService _bookService; - - private readonly int maxLateDonationDays; private readonly IConfiguration _configuration; + public new const string JobName = "LateDonationNotification"; + public const string EmailTemplateName = "LateDonationNotification"; + public const string EmailAdminsSubject = "SHAREBOOK - STATUS DO DIA."; + public const string EmailDonatorHardSubject = "Doação abandonada no Sharebook. Urgente!"; + public const string EmailDonatorSoftSubject = "Lembrete do Sharebook"; + public const string ConfigMaxLateDonationDaysKey = "SharebookSettings:MaxLateDonationDays"; + private readonly int maxLateDonationDays; public LateDonationNotification(IJobHistoryRepository jobHistoryRepo, @@ -26,7 +31,6 @@ public LateDonationNotification(IJobHistoryRepository jobHistoryRepo, IEmailService emailService, IEmailTemplate emailTemplate, IConfiguration configuration) : base(jobHistoryRepo) { - JobName = "LateDonationNotification"; Description = "Notifica o facilitador e doador com lista de doações em atraso " + "ordenado pelo mais atrasado."; Interval = Interval.Dayly; @@ -38,7 +42,7 @@ public LateDonationNotification(IJobHistoryRepository jobHistoryRepo, _emailTemplate = emailTemplate; _configuration = configuration; - maxLateDonationDays = int.Parse(_configuration["SharebookSettings:MaxLateDonationDays"]); + maxLateDonationDays = int.Parse(_configuration[ConfigMaxLateDonationDaysKey]); } @@ -93,17 +97,15 @@ private async Task SendEmailAdminAsync(IList booksLate, BookStatsDTO statu htmlTable += ""; - var emailSubject = "SHAREBOOK - STATUS DO DIA."; - var vm = new { htmlTable, totalWaitingApproval = status.TotalWaitingApproval, totalLate = booksLate.Count, totalOk = status.TotalOk }; - var emailBodyHTML = await _emailTemplate.GenerateHtmlFromTemplateAsync("LateDonationNotification", vm); + var emailBodyHTML = await _emailTemplate.GenerateHtmlFromTemplateAsync(EmailTemplateName, vm); - await _emailService.SendToAdminsAsync(emailBodyHTML, emailSubject); + await _emailService.SendToAdminsAsync(emailBodyHTML, EmailAdminsSubject); } private string GetWhatsappLink(string phone) @@ -148,9 +150,7 @@ private async Task SendEmailDonatorHardAsync(User donator) html += "

Sinceramente,

"; html += "

Sharebook

"; - var emailSubject = "Doação abandonada no Sharebook. Urgente!"; - - await _emailService.SendAsync(donator.Email, donator.Name, html, emailSubject, copyAdmins: true, highPriority: true); + await _emailService.SendAsync(donator.Email, donator.Name, html, EmailDonatorHardSubject, copyAdmins: true, highPriority: true); } private async Task SendEmailDonatorSoftAsync(User donator) @@ -161,9 +161,7 @@ private async Task SendEmailDonatorSoftAsync(User donator) html += "

Obrigado. Qualquer dúvida pode entrar em contato com o seu facilitador. É um prazer ajudar. =)

"; html += "

Sharebook

"; - var emailSubject = "Lembrete do Sharebook"; - - await _emailService.SendAsync(donator.Email, donator.Name, html, emailSubject, copyAdmins: false, highPriority: true); + await _emailService.SendAsync(donator.Email, donator.Name, html, EmailDonatorSoftSubject, copyAdmins: false, highPriority: true); } #endregion From 19386b0ef778f1174ba1c856b0f7b1e397697900 Mon Sep 17 00:00:00 2001 From: Henrique Holtz Date: Sat, 15 Jun 2024 07:23:41 -0300 Subject: [PATCH 35/37] fix: UnitOfWork => Avoiding exception when is called "DisposeAsync" --- ShareBook/ShareBook.Repository/UoW/UnitOfWork.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ShareBook/ShareBook.Repository/UoW/UnitOfWork.cs b/ShareBook/ShareBook.Repository/UoW/UnitOfWork.cs index 68d05411..e5bedf64 100644 --- a/ShareBook/ShareBook.Repository/UoW/UnitOfWork.cs +++ b/ShareBook/ShareBook.Repository/UoW/UnitOfWork.cs @@ -1,4 +1,5 @@ using System; +using System.Reflection.Metadata.Ecma335; using System.Threading.Tasks; namespace ShareBook.Repository.UoW @@ -12,6 +13,10 @@ public class UnitOfWork : IUnitOfWork public async Task BeginTransactionAsync() => await _context.Database.BeginTransactionAsync(); public async Task CommitAsync() => await _context.Database.CommitTransactionAsync(); public async Task RollbackAsync() => await _context.Database.RollbackTransactionAsync(); - public async ValueTask DisposeAsync() => await _context.Database.CurrentTransaction?.RollbackAsync(); + public async ValueTask DisposeAsync() + { + if (_context?.Database?.CurrentTransaction != null) + await _context.Database.CurrentTransaction.RollbackAsync(); + } } } From 2b386cd955a40d215ec20002cd0011614a181013 Mon Sep 17 00:00:00 2001 From: Henrique Holtz Date: Sat, 15 Jun 2024 09:00:34 -0300 Subject: [PATCH 36/37] fix: MeetupService.SearchAsync => Removing "StringComparison" to avoid the following error : "comparisonType: InvariantCultureIgnoreCase))' could not be translated. Additional information: Translation of method 'string.Contains' failed" --- ShareBook/ShareBook.Service/Meetup/MeetupService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ShareBook/ShareBook.Service/Meetup/MeetupService.cs b/ShareBook/ShareBook.Service/Meetup/MeetupService.cs index 9ab90afb..4603effb 100644 --- a/ShareBook/ShareBook.Service/Meetup/MeetupService.cs +++ b/ShareBook/ShareBook.Service/Meetup/MeetupService.cs @@ -218,7 +218,7 @@ private async Task UploadCoverAsync(string coverUrl, string eventName) public async Task> SearchAsync(string criteria) { return await _repository.Get() - .Where(m => m.Active && ( m.Title.Contains(criteria, StringComparison.InvariantCultureIgnoreCase) || m.Description.Contains(criteria, StringComparison.InvariantCultureIgnoreCase))) + .Where(m => m.Active && (m.Title.Contains(criteria) || m.Description.Contains(criteria))) .OrderByDescending(m => m.CreationDate) .ToListAsync(); } From e3c49523634daf3a16cb244ecc1af057458bdaea Mon Sep 17 00:00:00 2001 From: Henrique Holtz Date: Sat, 15 Jun 2024 09:46:40 -0300 Subject: [PATCH 37/37] feat: Adding postman collection ready to execute against development environment + infos about in the README --- README.md | 11 + ShareBook API - Tests.postman_collection.json | 922 ++++++++++++++++++ 2 files changed, 933 insertions(+) create mode 100644 ShareBook API - Tests.postman_collection.json diff --git a/README.md b/README.md index 924149d9..28833056 100644 --- a/README.md +++ b/README.md @@ -85,3 +85,14 @@ dotnet test ./ShareBook/ShareBook.Test.Unit/ShareBook.Test.Unit.csproj # clean dotnet clean ./ShareBook/ShareBook.Api/ShareBook.Api.csproj --verbosity quiet ``` + +## **[WIP] 8 - Como testar a aplicação usando postman** + +Atenção! Este passo está em construção e ainda exige alguns passos manuais. Em breve será automatizado. + +Consiste em usar uma collection do postman (v2.1) para testar os resultados das requisições. No momento a collection está pronta para usa no ambiente de dev. + +1. Obter o arquivo [ShareBook API - Tests.postman_collection.json](./ShareBook%20API%20-%20Tests.postman_collection.json) do repositório +2. Usando a ferramenta postman, clique em importar e selecione o arquivo +3. Com o botão direito na collection `ShareBook API - Tests`, clique em `Run collection` +4. Na nova janela clique em executar. Após executar verifique a quantidade de erros. diff --git a/ShareBook API - Tests.postman_collection.json b/ShareBook API - Tests.postman_collection.json new file mode 100644 index 00000000..c40a2f37 --- /dev/null +++ b/ShareBook API - Tests.postman_collection.json @@ -0,0 +1,922 @@ +{ + "info": { + "_postman_id": "f7913a70-c6f4-4636-86a3-347efa40216f", + "name": "ShareBook API - Tests", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", + "_exporter_id": "29881360" + }, + "item": [ + { + "name": "Anonymous", + "item": [ + { + "name": "assets/img/logo.png", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"OK/200 and Content-Type is image/png\", function () {\r", + " pm.response.to.have.status(200);\r", + " pm.response.to.have.header(\"Content-Type\");\r", + " pm.expect(pm.response.headers.get('Content-Type')).to.be.equal('image/png')\r", + "});\r", + "\r", + "// TODO: Add validations to the json values" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{sharebookUrl}}assets/img/logo.png", + "host": [ + "{{sharebookUrl}}assets" + ], + "path": [ + "img", + "logo.png" + ] + } + }, + "response": [] + }, + { + "name": "AvailableBooks", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"OK/200 and json\", function () {\r", + " pm.response.to.have.status(200);\r", + " pm.response.json();\r", + "});\r", + "\r", + "// TODO: Add validations to the json values" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{sharebookUrl}}api/book/AvailableBooks", + "host": [ + "{{sharebookUrl}}api" + ], + "path": [ + "book", + "AvailableBooks" + ] + } + }, + "response": [] + }, + { + "name": "Books/freightOptions", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"OK/200 and json\", function () {\r", + " pm.response.to.have.status(200);\r", + " pm.response.json();\r", + "});\r", + "\r", + "// TODO: Add validations to the json values" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "auth": { + "type": "noauth" + }, + "method": "GET", + "header": [], + "url": { + "raw": "{{sharebookUrl}}api/Book/freightOptions", + "host": [ + "{{sharebookUrl}}api" + ], + "path": [ + "Book", + "freightOptions" + ] + } + }, + "response": [] + }, + { + "name": "Books/Slug - 200", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"OK/200 and json\", function () {\r", + " // This Slug \"volta-ao-mundo-em-80-dias\" cames from \"ShareBookSeeder.Seed()\"\r", + " pm.response.to.have.status(200);\r", + " pm.response.json();\r", + "});\r", + "\r", + "// TODO: Add validations to the json values" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "auth": { + "type": "noauth" + }, + "method": "GET", + "header": [], + "url": { + "raw": "{{sharebookUrl}}api/Book/Slug/volta-ao-mundo-em-80-dias", + "host": [ + "{{sharebookUrl}}api" + ], + "path": [ + "Book", + "Slug", + "volta-ao-mundo-em-80-dias" + ] + } + }, + "response": [] + }, + { + "name": "Book/Slug - 404", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"404 - Not Found\", function () {\r", + " pm.response.to.have.status(404);\r", + "});\r", + "\r", + "// TODO: Add validations to the json values" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{SharebookAccessToken}}", + "type": "string" + } + ] + }, + "method": "GET", + "header": [], + "url": { + "raw": "{{sharebookUrl}}api/Book/Slug/inexistent-aleatory", + "host": [ + "{{sharebookUrl}}api" + ], + "path": [ + "Book", + "Slug", + "inexistent-aleatory" + ] + } + }, + "response": [] + }, + { + "name": "Meetups - Past", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"OK/200 and json\", function () {\r", + " pm.response.to.have.status(200);\r", + " pm.response.json();\r", + "});\r", + "\r", + "// TODO: Add validations to the json values" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{sharebookUrl}}api/Meetup?page=1&pagesize=10&upcoming=false", + "host": [ + "{{sharebookUrl}}api" + ], + "path": [ + "Meetup" + ], + "query": [ + { + "key": "page", + "value": "1" + }, + { + "key": "pagesize", + "value": "10" + }, + { + "key": "upcoming", + "value": "false" + } + ] + } + }, + "response": [] + }, + { + "name": "Meetups - Upcoming", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"OK/200 and json\", function () {\r", + " pm.response.to.have.status(200);\r", + " pm.response.json();\r", + "});\r", + "\r", + "// TODO: Add validations to the json values" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{sharebookUrl}}api/Meetup?page=1&pagesize=50&upcoming=true", + "host": [ + "{{sharebookUrl}}api" + ], + "path": [ + "Meetup" + ], + "query": [ + { + "key": "page", + "value": "1" + }, + { + "key": "pagesize", + "value": "50" + }, + { + "key": "upcoming", + "value": "true" + } + ] + } + }, + "response": [] + }, + { + "name": "Meetups Search", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"OK/200 and json\", function () {\r", + " pm.response.to.have.status(200);\r", + " pm.response.json();\r", + "});\r", + "\r", + "// TODO: Add validations to the json values" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{sharebookUrl}}api/Meetup/search?criteria=QuAliDade", + "host": [ + "{{sharebookUrl}}api" + ], + "path": [ + "Meetup", + "search" + ], + "query": [ + { + "key": "criteria", + "value": "QuAliDade" + } + ] + } + }, + "response": [] + }, + { + "name": "Meetup \"Qualidade de vida\"", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"OK/200 and json\", function () {\r", + " pm.response.to.have.status(200);\r", + " pm.response.json();\r", + "});\r", + "\r", + "// TODO: Add validations to the json values" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{sharebookUrl}}api/Meetup/46b5e5ee-8d7c-417e-9872-11555ebb7bd2", + "host": [ + "{{sharebookUrl}}api" + ], + "path": [ + "Meetup", + "46b5e5ee-8d7c-417e-9872-11555ebb7bd2" + ] + } + }, + "response": [] + }, + { + "name": "Book/Random15Books", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"OK/200 and json\", function () {\r", + " pm.response.to.have.status(200);\r", + " pm.response.json();\r", + "});\r", + "\r", + "// TODO: Add validations to the json values" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "auth": { + "type": "noauth" + }, + "method": "GET", + "header": [], + "url": { + "raw": "{{sharebookUrl}}api/Book/Random15Books", + "host": [ + "{{sharebookUrl}}api" + ], + "path": [ + "Book", + "Random15Books" + ] + } + }, + "response": [] + }, + { + "name": "Book/Random15EBooks", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"OK/200 and json\", function () {\r", + " pm.response.to.have.status(200);\r", + " pm.response.json();\r", + "});\r", + "\r", + "// TODO: Add validations to the json values" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "auth": { + "type": "noauth" + }, + "method": "GET", + "header": [], + "url": { + "raw": "{{sharebookUrl}}api/Book/Random15EBooks", + "host": [ + "{{sharebookUrl}}api" + ], + "path": [ + "Book", + "Random15EBooks" + ] + } + }, + "response": [] + }, + { + "name": "Category", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"OK/200 and json\", function () {\r", + " pm.response.to.have.status(200);\r", + " pm.response.json();\r", + "});\r", + "\r", + "// TODO: Add validations to the json values" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "auth": { + "type": "noauth" + }, + "method": "GET", + "header": [], + "url": { + "raw": "{{sharebookUrl}}api/Category", + "host": [ + "{{sharebookUrl}}api" + ], + "path": [ + "Category" + ] + } + }, + "response": [] + }, + { + "name": "Operations/Ping", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"OK/200 and json\", function () {\r", + " pm.response.to.have.status(200);\r", + " pm.response.json();\r", + "});\r", + "\r", + "// TODO: Add validations to the json values" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "auth": { + "type": "noauth" + }, + "method": "GET", + "header": [], + "url": { + "raw": "{{sharebookUrl}}api/Operations/Ping", + "host": [ + "{{sharebookUrl}}api" + ], + "path": [ + "Operations", + "Ping" + ] + } + }, + "response": [] + } + ] + }, + { + "name": "Authenticated", + "item": [ + { + "name": "Login (web)", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"OK/200 and json\", function () {\r", + " pm.response.to.have.status(200);\r", + " pm.response.json();\r", + "});\r", + "\r", + "\r", + "// TODO: Add validations to the json values\r", + "// TODO: Verify the environment and use different logins or skip this test\r", + "\r", + "const sharebookAccessTokenName = 'SharebookAccessToken'\r", + "pm.test(\"Getting Access Token\", function () {\r", + " var jsonData = pm.response.json()\r", + " pm.expect(jsonData.value.accessToken.length > 100, 'Access Token').to.be.true\r", + " pm.collectionVariables.set(sharebookAccessTokenName, jsonData.value.accessToken)\r", + "});" + ], + "type": "text/javascript", + "packages": {} + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "// TODO: Verify the environment and use different logins or skip this test\r", + "\r", + "const sharebookAccessTokenName = 'SharebookAccessToken'\r", + "if (pm.collectionVariables.has(sharebookAccessTokenName))\r", + " pm.collectionVariables.set(sharebookAccessTokenName, '')" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "x-requested-with", + "value": "web" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n\t\"email\": \"raffacabofrio@gmail.com\",\r\n\t\"password\": \"123456\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{sharebookUrl}}/api/Account/Login", + "host": [ + "{{sharebookUrl}}" + ], + "path": [ + "api", + "Account", + "Login" + ] + } + }, + "response": [] + }, + { + "name": "Account", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"OK/200 and json\", function () {\r", + " pm.response.to.have.status(200);\r", + " pm.response.json();\r", + "});\r", + "\r", + "// TODO: Add validations to the json values" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{SharebookAccessToken}}", + "type": "string" + } + ] + }, + "method": "GET", + "header": [], + "url": { + "raw": "{{sharebookUrl}}api/Account", + "host": [ + "{{sharebookUrl}}api" + ], + "path": [ + "Account" + ] + } + }, + "response": [] + }, + { + "name": "Account/Profile", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"OK/200 and json\", function () {\r", + " pm.response.to.have.status(200);\r", + " pm.response.json();\r", + "});\r", + "\r", + "// TODO: Add validations to the json values" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{SharebookAccessToken}}", + "type": "string" + } + ] + }, + "method": "GET", + "header": [], + "url": { + "raw": "{{sharebookUrl}}api/Account/Profile", + "host": [ + "{{sharebookUrl}}api" + ], + "path": [ + "Account", + "Profile" + ] + } + }, + "response": [] + }, + { + "name": "Book", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"OK/200 and json\", function () {\r", + " pm.response.to.have.status(200);\r", + " pm.response.json();\r", + "});\r", + "\r", + "// TODO: Add validations to the json values" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{SharebookAccessToken}}", + "type": "string" + } + ] + }, + "method": "GET", + "header": [], + "url": { + "raw": "{{sharebookUrl}}api/Book", + "host": [ + "{{sharebookUrl}}api" + ], + "path": [ + "Book" + ] + } + }, + "response": [] + }, + { + "name": "Book/MyDonations", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"OK/200 and json\", function () {\r", + " pm.response.to.have.status(200);\r", + " pm.response.json();\r", + "});\r", + "\r", + "// TODO: Add validations to the json values" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{SharebookAccessToken}}", + "type": "string" + } + ] + }, + "method": "GET", + "header": [], + "url": { + "raw": "{{sharebookUrl}}api/Book/MyDonations", + "host": [ + "{{sharebookUrl}}api" + ], + "path": [ + "Book", + "MyDonations" + ] + } + }, + "response": [] + } + ] + }, + { + "name": "Unauthorized", + "item": [ + { + "name": "Account", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Should be Unauthorized/401\", function () {\r", + " pm.response.to.have.status(401);\r", + "});" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{sharebookUrl}}api/Account", + "host": [ + "{{sharebookUrl}}api" + ], + "path": [ + "Account" + ] + } + }, + "response": [] + }, + { + "name": "Account/Profile", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Should be Unauthorized/401\", function () {\r", + " pm.response.to.have.status(401);\r", + "});" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{sharebookUrl}}api/Account/Profile", + "host": [ + "{{sharebookUrl}}api" + ], + "path": [ + "Account", + "Profile" + ] + } + }, + "response": [] + }, + { + "name": "Book", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Should be Unauthorized/401\", function () {\r", + " pm.response.to.have.status(401);\r", + "});" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{sharebookUrl}}api/Book", + "host": [ + "{{sharebookUrl}}api" + ], + "path": [ + "Book" + ] + } + }, + "response": [] + } + ] + } + ], + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "packages": {}, + "exec": [ + "const sharebookUrlName = 'sharebookUrl'\r", + "if (pm.globals.has(sharebookUrlName))\r", + " console.log(`Running using ${pm.globals.get(sharebookUrlName)}`)\r", + "else {\r", + " const fallbackUrl = 'https://dev.sharebook.com.br/'\r", + " console.log(`The global variable ${sharebookUrlName} isn't found. Using ${fallbackUrl} as default value... `)\r", + " pm.globals.set(sharebookUrlName, fallbackUrl)\r", + "}" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "packages": {}, + "exec": [ + "" + ] + } + } + ], + "variable": [ + { + "key": "SharebookAccessToken", + "value": "" + } + ] +} \ No newline at end of file