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 diff --git a/ShareBook/ShareBook.Api/Controllers/AccountController.cs b/ShareBook/ShareBook.Api/Controllers/AccountController.cs index 08ecefb1..c8dee7eb 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")] @@ -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); @@ -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) { @@ -126,7 +126,7 @@ public IActionResult Post([FromBody] RegisterUserDTO registerUserDto, [FromServi [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) { @@ -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); @@ -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); @@ -209,26 +209,26 @@ public IActionResult Update([FromBody] UpdateUserVM updateUserVM, [FromServices] [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")] [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); + var result = await _userService.ConfirmHashCodePasswordAsync(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); + var resultChangePasswordUser = await _userService.ChangeUserPasswordAsync(user, newPassword); if (!resultChangePasswordUser.Success) return BadRequest(resultChangePasswordUser); @@ -237,14 +237,14 @@ public IActionResult ChangeUserPasswordByHashCode([FromBody] ChangeUserPasswordB } [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(); } @@ -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 435d1cde..1ef0affc 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() @@ -78,37 +78,37 @@ 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."); } [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); } @@ -125,15 +125,15 @@ 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}")] - 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 requesters = await _bookUserService.GetRequestersListAsync(bookId); var requestersVM = _mapper.Map>(requesters); return Ok(requestersVM); @@ -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,38 +152,38 @@ 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(); } [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); } [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,31 +222,31 @@ 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(); - if (_IsDonator(requestBookVM.BookId, user) && !_IsAdmin(user)) //Permitido solicitar o próprio livro somente para Admin + User user = await GetUserAsync(); + 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!" }); } [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); @@ -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(); + if (!await _IsBookOwnerAsync(bookId)) return Unauthorized(); - _bookUserService.DonateBook(bookId, donateBookUserVM.UserId, donateBookUserVM.Note); + await _bookUserService.DonateBookAsync(bookId, donateBookUserVM.UserId, donateBookUserVM.Note); var result = new Result { @@ -301,15 +301,15 @@ public IActionResult DonateBook(Guid bookId, [FromBody] DonateBookUserVM 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(); } @@ -353,9 +353,9 @@ public IActionResult InformTrackingNumber(Guid bookId, [FromBody] TrackinNumberB [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(); } @@ -364,9 +364,9 @@ 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); + var book = await _service.GetBookWithAllUsersAsync(bookId); var donor = _mapper.Map(book.User); var facilitator = _mapper.Map(book.UserFacilitator); @@ -380,10 +380,10 @@ 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); + await _accessHistoryService.InsertVisitorAsync(book.User, visitor, visitorProfile); return Ok(result); @@ -419,19 +419,19 @@ 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); + await _service.RenewChooseDateAsync(bookId); return Ok(); } // 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; @@ -439,22 +439,22 @@ private bool _IsBookOwner(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; } - 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,13 +464,13 @@ 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); - var book = _service.GetBookWithAllUsers(bookId); + var book = await _service.GetBookWithAllUsersAsync(bookId); // Ganhador var winner = book.WinnerUser(); @@ -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/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/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..4bb7f27f 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 { @@ -48,12 +49,12 @@ 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 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.Api/Controllers/MeetupController.cs b/ShareBook/ShareBook.Api/Controllers/MeetupController.cs index 6fba24f5..24004cc7 100644 --- a/ShareBook/ShareBook.Api/Controllers/MeetupController.cs +++ b/ShareBook/ShareBook.Api/Controllers/MeetupController.cs @@ -20,19 +20,18 @@ 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}")] - 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.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/Generic/IRepositoryGeneric.cs b/ShareBook/ShareBook.Repository/Repository/Generic/IRepositoryGeneric.cs index 96d75a75..daa4b3a6 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); @@ -36,21 +32,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. /// @@ -58,101 +39,36 @@ 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); - /// - /// 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); + 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); - - /// - /// 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); + 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); - - /// - /// 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. - /// - /// 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); - - void Delete(params object[] keyValues); - - void Delete(TEntity entity); + 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 212c9854..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; @@ -53,7 +52,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( @@ -161,49 +160,16 @@ public async Task DeleteAsync(TEntity entity) public IQueryable Get() => _dbSet; - public TEntity Find(object keyValue) => _dbSet.Find(keyValue); + public async Task FindAsync(Expression> filter) => await FindAsync(null, filter); - public TEntity Find(IncludeList includes, object keyValue) => FindAsync(includes, keyValue).GetAwaiter().GetResult(); + public async Task> GetAsync(Expression> filter, Expression> order) + => await GetAsync(filter, order, null); - public TEntity Find(Expression> filter) => FindAsync(null, filter).GetAwaiter().GetResult(); + public async Task> GetAsync(Expression> filter, Expression> order, IncludeList includes) + => await GetAsync(filter, order, 1, int.MaxValue, includes); - 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); - - 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 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(); + 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.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/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 7d1a83b9..e5bedf64 100644 --- a/ShareBook/ShareBook.Repository/UoW/UnitOfWork.cs +++ b/ShareBook/ShareBook.Repository/UoW/UnitOfWork.cs @@ -1,4 +1,8 @@ -namespace ShareBook.Repository.UoW +using System; +using System.Reflection.Metadata.Ecma335; +using System.Threading.Tasks; + +namespace ShareBook.Repository.UoW { public class UnitOfWork : IUnitOfWork { @@ -6,10 +10,13 @@ public class UnitOfWork : IUnitOfWork 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() + { + if (_context?.Database?.CurrentTransaction != null) + await _context.Database.CurrentTransaction.RollbackAsync(); + } } } 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 f4ac2037..67d9f697 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.SendMessageAsync(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() @@ -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,20 +160,20 @@ 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 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.SendEmailNewBookInserted(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 => @@ -300,16 +297,16 @@ public bool UserRequestedBook(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 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() @@ -346,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); @@ -372,24 +369,22 @@ 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) { - 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(); - - return books.FirstOrDefault(); + 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) + .FirstOrDefaultAsync(); } - public void RenewChooseDate(Guid bookId) + public async Task RenewChooseDateAsync(Guid bookId) { - var book = _repository.Find(bookId); + var book = await _repository.FindAsync(bookId); if (book == null) throw new ShareBookException(ShareBookException.Error.NotFound); @@ -398,15 +393,15 @@ public void RenewChooseDate(Guid bookId) book.Status = BookStatus.Available; book.ChooseDate = DateTime.Now.AddDays(10); - _repository.Update(book); + await _repository.UpdateAsync(book); } #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,15 +438,16 @@ 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) { + // TODO: Migrate to async/await (P.s: breaking unit tests) 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,21 +463,21 @@ 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(); - 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/BooksEmailService.cs b/ShareBook/ShareBook.Service/Book/BooksEmailService.cs index 509bb044..52ec5fe8 100644 --- a/ShareBook/ShareBook.Service/Book/BooksEmailService.cs +++ b/ShareBook/ShareBook.Service/Book/BooksEmailService.cs @@ -36,10 +36,10 @@ 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); + book.User = await _userService.FindAsync(book.UserId); if (book.User.AllowSendingEmail) { @@ -50,14 +50,14 @@ public async Task SendEmailBookApproved(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); } } - public void SendEmailBookReceived(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) { @@ -68,18 +68,17 @@ 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.SendAsync(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); + book.User = await _userService.FindAsync(book.UserId); - var userStats = _userService.GetStats(book.UserId); + var userStats = await _userService.GetStatsAsync(book.UserId); await SendEmailNewBookInsertedToAdministrators(book, userStats); @@ -96,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) @@ -105,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/Book/IBookService.cs b/ShareBook/ShareBook.Service/Book/IBookService.cs index c2a061cd..e356e0f8 100644 --- a/ShareBook/ShareBook.Service/Book/IBookService.cs +++ b/ShareBook/ShareBook.Service/Book/IBookService.cs @@ -11,42 +11,42 @@ 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(); - IList AvailableBooks(); + Task> AvailableBooksAsync(); - IList Random15Books(); + Task> Random15BooksAsync(); - IList Random15EBooks(); + Task> Random15EBooksAsync(); - 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); + Task> GetAllAsync(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(); 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); - BookStatsDTO GetStats(); + Task RenewChooseDateAsync(Guid bookId); + Task GetStatsAsync(); } } 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/BookUserEmailService.cs b/ShareBook/ShareBook.Service/BookUser/BookUserEmailService.cs index 38b290f1..2579cc53 100644 --- a/ShareBook/ShareBook.Service/BookUser/BookUserEmailService.cs +++ b/ShareBook/ShareBook.Service/BookUser/BookUserEmailService.cs @@ -42,11 +42,11 @@ 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) - bookDonated.User = _userService.Find(bookUser.Book.UserId); + bookDonated.User = await _userService.FindAsync(bookUser.Book.UserId); if (bookDonated.User.AllowSendingEmail) { @@ -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,18 +74,18 @@ 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)) 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); @@ -104,7 +104,7 @@ public async Task SendEmailBookDonor(BookUser bookUser, Book bookRequested) }; // push notification - _notificationService.SendNotificationByEmail( + await _notificationService.SendNotificationByEmailAsync( bookRequested.User.Email, $"Seu livro foi solicitado", $" O Interessado é {vm.RequestingUser.NickName}" ); @@ -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,11 +153,11 @@ 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) - bookUser.User = _userService.Find(bookUser.UserId); + bookUser.User = await _userService.FindAsync(bookUser.UserId); if (bookUser.User.AllowSendingEmail) { @@ -173,10 +173,10 @@ public async Task SendEmailBookInterested(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.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 { @@ -215,28 +215,30 @@ public async Task SendEmailDonationDeclined(Book book, BookUser bookUserWinner, 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.Send(bookUser.User.Email, bookUser.User.Name, html, emailSubject).Wait(); + await _emailService.SendAsync(bookUser.User.Email, bookUser.User.Name, html, emailSubject); }); } - 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); - bookUsers.ForEach(bookUser => + bookUsers.ForEach(async (bookUser) => { + // TODO: Find out a better approach instead of awaiting one by one if (bookUser.User.AllowSendingEmail) - _emailService.Send(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}."); }); } - public async Task SendEmailBookCanceledToAdminsAndDonor(BookCancelationDTO dto) + public async Task SendEmailBookCanceledToAdminsAndDonorAsync(BookCancelationDTO dto) { var donor = dto.Book.User; @@ -249,10 +251,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(); + await _emailService.SendAsync(donor.Email, donor.Name, html, BookCanceledTitle, copyAdmins: true, highPriority: true); } - public async Task SendEmailTrackingNumberInformed(BookUser bookUserWinner, Book book) + public async Task SendEmailTrackingNumberInformedAsync(BookUser bookUserWinner, Book book) { if (bookUserWinner.User.AllowSendingEmail) { @@ -265,15 +267,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 5d850ebb..a769d4f2 100644 --- a/ShareBook/ShareBook.Service/BookUser/BookUserService.cs +++ b/ShareBook/ShareBook.Service/BookUser/BookUserService.cs @@ -46,24 +46,24 @@ 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(); - - public void Insert(Guid bookId, string reason) + .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) { //obtem o livro requisitado e o doador - var bookRequested = _bookService.GetBookWithAllUsers(bookId); + var bookRequested = await _bookService.GetBookWithAllUsersAsync(bookId); var bookUser = new BookUser() { BookId = bookId, @@ -72,26 +72,26 @@ public void Insert(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 (_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); + await MaxRequestsValidationAsync(bookRequested); - _bookUsersEmailService.SendEmailBookDonor(bookUser, bookRequested).Wait(); - _bookUsersEmailService.SendEmailBookInterested(bookUser, bookRequested).Wait(); + 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,25 +99,25 @@ private void MaxRequestsValidation(Book bookRequested) bookRequested.Status = BookStatus.AwaitingDonorDecision; bookRequested.ChooseDate = DateTime.Today.AddDays(1); - _bookRepository.Update(bookRequested); + await _bookRepository.UpdateAsync(bookRequested); - _bookUsersEmailService.SendEmailMaxRequests(bookRequested); + await _bookUsersEmailService.SendEmailMaxRequestsAsync(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); + var book = await _bookService.FindAsync(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,62 +127,60 @@ public void DonateBook(Guid bookId, Guid userId, string note) bookUserAccepted.UpdateBookUser(DonationStatus.Donated, note); - _bookUserRepository.Update(bookUserAccepted); + await _bookUserRepository.UpdateAsync(bookUserAccepted); - DeniedBookUsers(bookId); + await DeniedBookUsersAsync(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.SendEmailBookDonatedAsync(bookUserAccepted); // avisa os perdedores :/ - NotifyInterestedAboutBooksWinner(bookId).Wait(); + await NotifyInterestedAboutBooksWinnerAsync(bookId); // avisa o doador - _bookUsersEmailService.SendEmailBookDonatedNotifyDonor(bookUserAccepted.Book, bookUserAccepted.User).Wait(); + await _bookUsersEmailService.SendEmailBookDonatedNotifyDonorAsync(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); - var bookUsers = _bookUserRepository.Get().Where(x => x.BookId == dto.Book.Id).ToList(); - 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.SendEmailBookCanceledToAdminsAndDonorAsync(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() @@ -190,7 +188,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 => @@ -202,16 +200,16 @@ public PagedList GetRequestsByUser(int page, int itemsPerPage) return result; } - public async Task NotifyInterestedAboutBooksWinner(Guid bookId) + public async Task NotifyInterestedAboutBooksWinnerAsync(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; @@ -220,72 +218,66 @@ 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 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.SendEmailDonationCanceledAsync(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.SendEmailTrackingNumberInformedAsync(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 fa000e10..a6d94fb2 100644 --- a/ShareBook/ShareBook.Service/BookUser/IBookUserService.cs +++ b/ShareBook/ShareBook.Service/BookUser/IBookUserService.cs @@ -9,28 +9,28 @@ namespace ShareBook.Service { public interface IBookUserService { - void Insert(Guid bookId, string reason); + Task InsertAsync(Guid bookId, string reason); - IList GetGranteeUsersByBookId(Guid bookId); + Task> GetGranteeUsersByBookIdAsync(Guid bookId); - IList GetRequestersList(Guid bookId); + Task> GetRequestersListAsync(Guid bookId); - void DonateBook(Guid bookId, Guid userId, string note); + 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 /// /// - Task NotifyInterestedAboutBooksWinner(Guid bookId); + Task NotifyInterestedAboutBooksWinnerAsync(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/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..da2a9f60 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); + 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); } - 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,15 +78,15 @@ 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); + var message = await FormatEmailAsync(emailRecipient, nameRecipient, messageText, subject, copyAdmins); var client = new SmtpClient(); @@ -94,13 +94,13 @@ public async Task SendSmtp(string emailRecipient, string nameRecipient, string m 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,16 +120,16 @@ private MimeMessage FormatEmail(string emailRecipient, string nameRecipient, str return message; } - private InternetAddressList FormatEmailGetAdminEmails() + private async Task FormatEmailGetAdminEmailsAsync() { - 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) @@ -140,14 +140,14 @@ 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() { var log = new List(); @@ -157,25 +157,25 @@ public async Task> ProcessBounceMessages() 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 { @@ -184,27 +184,27 @@ public async Task> ProcessBounceMessages() } - _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; 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(); } @@ -214,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; diff --git a/ShareBook/ShareBook.Service/Email/IEmailService.cs b/ShareBook/ShareBook.Service/Email/IEmailService.cs index bf9e4a40..cb3435f8 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; @@ -7,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/Generic/BaseService.cs b/ShareBook/ShareBook.Service/Generic/BaseService.cs index 422614d8..c46dd723 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 { @@ -24,87 +26,69 @@ 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 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 async Task FindAsync(Expression> filter) + => await _repository.FindAsync(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); + public async Task> GetAsync(Expression> order, int page, int itemsPerPage, IncludeList includes) + => await _repository.GetAsync(order, page, itemsPerPage, includes); - public PagedList Get(Expression> order, IncludeList includes) - => _repository.Get(order, includes); + public virtual async Task> GetAsync(Expression> filter, Expression> order, int page, int itemsPerPage) + => await _repository.GetAsync(filter, order, page, itemsPerPage); - 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) - => _repository.Get(order, page, itemsPerPage); - - 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 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..86292999 100644 --- a/ShareBook/ShareBook.Service/Generic/IBaseService.cs +++ b/ShareBook/ShareBook.Service/Generic/IBaseService.cs @@ -2,32 +2,33 @@ 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 AnyAsync(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. /// /// 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. @@ -35,62 +36,22 @@ 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); - - /// - /// 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, without child objects. - /// - /// First Page = 1 - PagedList Get(Expression> order, int page, int itemsPerPage); + Task FindAsync(IncludeList includes, Expression> filter); /// /// 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); - - /// - /// 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); - 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..da40ad44 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(); @@ -61,10 +62,10 @@ public void Anonymize(UserAnonymizeDTO dto) RemoveLogs(user); // 5 - Notifica os adms. - _userEmailService.SendEmailAnonymizeNotifyAdms(dto); + await _userEmailService.SendEmailAnonymizeNotifyAdmsAsync(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/Meetup/MeetupService.cs b/ShareBook/ShareBook.Service/Meetup/MeetupService.cs index d7d1b04a..4603effb 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; @@ -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; @@ -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(); } 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); } 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"; } 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); } diff --git a/ShareBook/ShareBook.Service/User/IUserEmailService.cs b/ShareBook/ShareBook.Service/User/IUserEmailService.cs index 97f89baf..61e2d3ed 100644 --- a/ShareBook/ShareBook.Service/User/IUserEmailService.cs +++ b/ShareBook/ShareBook.Service/User/IUserEmailService.cs @@ -7,8 +7,8 @@ namespace ShareBook.Service public interface IUserEmailService { Task SendEmailForgotMyPasswordToUserAsync(User user); - void SendEmailRequestParentAproval(RegisterUserDTO userDto, User user); - void SendEmailParentAprovedNotifyUser(User user); - void SendEmailAnonymizeNotifyAdms(UserAnonymizeDTO dto); + Task SendEmailRequestParentAprovalAsync(RegisterUserDTO userDto, User user); + Task SendEmailParentAprovedNotifyUserAsync(User user); + Task SendEmailAnonymizeNotifyAdmsAsync(UserAnonymizeDTO dto); } } diff --git a/ShareBook/ShareBook.Service/User/IUserService.cs b/ShareBook/ShareBook.Service/User/IUserService.cs index d6a054b6..2f84c37a 100644 --- a/ShareBook/ShareBook.Service/User/IUserService.cs +++ b/ShareBook/ShareBook.Service/User/IUserService.cs @@ -4,23 +4,24 @@ using ShareBook.Service.Generic; using System; using System.Collections.Generic; +using System.Threading.Tasks; namespace ShareBook.Service { public interface IUserService : IBaseService { - Result AuthenticationByEmailAndPassword(User user); + Task> AuthenticationByEmailAndPasswordAsync(User user); bool IsValidPassword(User user, string decryptedPass); - new Result Update(User user); - Result ValidOldPasswordAndChangeUserPassword(User user, string newPassword); - Result ChangeUserPassword(User user, string newPassword); - Result GenerateHashCodePasswordAndSendEmailToUser(string email); - Result ConfirmHashCodePassword(string hashCodePassword); + new Task> UpdateAsync(User user); + Task> ValidOldPasswordAndChangeUserPasswordAsync(User user, string newPassword); + Task> ChangeUserPasswordAsync(User user, string newPassword); + Task GenerateHashCodePasswordAndSendEmailToUserAsync(string email); + Task ConfirmHashCodePasswordAsync(string hashCodePassword); IList GetFacilitators(Guid userIdDonator); IList GetAdmins(); - IList GetBySolicitedBookCategory(Guid BookCategoryId); - UserStatsDTO GetStats(Guid? userId); - Result Insert(RegisterUserDTO userDto); - void ParentAproval(string parentHashCodeAproval); + Task> GetBySolicitedBookCategoryAsync(Guid bookCategoryId); + Task GetStatsAsync(Guid? userId); + 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 539507cf..58d6f106 100644 --- a/ShareBook/ShareBook.Service/User/UserEmailService.cs +++ b/ShareBook/ShareBook.Service/User/UserEmailService.cs @@ -31,43 +31,39 @@ 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 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.SendAsync(userDto.ParentEmail, "Pais", html, title); } - 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.SendAsync(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.SendToAdminsAsync(html, title); } } } diff --git a/ShareBook/ShareBook.Service/User/UserService.cs b/ShareBook/ShareBook.Service/User/UserService.cs index d5166c07..af52d35d 100644 --- a/ShareBook/ShareBook.Service/User/UserService.cs +++ b/ShareBook/ShareBook.Service/User/UserService.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading; +using System.Threading.Tasks; using AutoMapper; using FluentValidation; using Microsoft.EntityFrameworkCore; @@ -45,13 +46,13 @@ 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); string decryptedPass = user.Password; - user = _repository.Find(e => e.Email == user.Email); + user = await _repository.FindAsync(e => e.Email == user.Email); if (user == null) { @@ -68,7 +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; - _userRepository.Update(user); + await _userRepository.UpdateAsync(user); if (!IsValidPassword(user, decryptedPass)) { @@ -92,12 +93,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); @@ -106,23 +107,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(); @@ -130,10 +131,10 @@ 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 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,31 +158,31 @@ 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) + 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) @@ -189,17 +190,16 @@ public Result ChangeUserPassword(User user, string newPassword) user.ChangePassword(newPassword); user = GetUserEncryptedPass(user); - // TODO: Remove "GetAwaiter().GetResult()" - user = _userRepository.UpdatePassword(user).GetAwaiter().GetResult(); + user = await _userRepository.UpdatePasswordAsync(user); result.Value = UserCleanup(user); return result; } - public Result GenerateHashCodePasswordAndSendEmailToUser(string email) + 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) { @@ -208,17 +208,17 @@ 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; } - 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."); @@ -268,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; @@ -305,33 +306,33 @@ 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) + 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."); @@ -340,9 +341,9 @@ 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); + await _userEmailService.SendEmailParentAprovedNotifyUserAsync(user); } diff --git a/ShareBook/ShareBook.Test.Unit/Jobs/0 - CancelAbandonedDonationsTests.cs b/ShareBook/ShareBook.Test.Unit/Jobs/0 - CancelAbandonedDonationsTests.cs new file mode 100644 index 00000000..891a770a --- /dev/null +++ b/ShareBook/ShareBook.Test.Unit/Jobs/0 - CancelAbandonedDonationsTests.cs @@ -0,0 +1,80 @@ +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 CancelAbandonedDonationsTests + { + private readonly Mock _mockJobHistoryRepository = new(); + private readonly Mock _mockBookService = new(); + private readonly Mock _mockBookUserService = new(); + private readonly Mock _mockConfiguration = new(); + private static int _maxLateDonationDaysAutoCancel = 90; + private static List _allBooks = new List { + BookMock.GetLordTheRings(), + BookMock.GetLordTheRings(), + BookMock.GetLordTheRings(), + BookMock.GetLordTheRings(), + }; + + 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, 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(); + + 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.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/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.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/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.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/BookUserServiceTests.cs b/ShareBook/ShareBook.Test.Unit/Services/BookUserServiceTests.cs index 860f0c80..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,7 +8,9 @@ using ShareBook.Service.Muambator; using ShareBook.Test.Unit.Mocks; using System; +using System.Linq.Expressions; using System.Threading; +using System.Threading.Tasks; using Xunit; namespace ShareBook.Test.Unit.Services @@ -43,14 +46,15 @@ public BookUserServiceTests() bookServiceMock.SetReturnsDefault(true); - bookServiceMock.Setup(s => s.GetBookWithAllUsers(It.IsAny())).Returns(() => + bookServiceMock.Setup(s => s.AnyAsync(It.IsAny>>())).ReturnsAsync(true); + 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 +64,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.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.Test.Unit/Services/UserServiceTests.cs b/ShareBook/ShareBook.Test.Unit/Services/UserServiceTests.cs index 55e5134a..c799d891 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 { @@ -45,22 +46,22 @@ 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(); }); - userRepositoryMock.Setup(repo => repo.Update(It.IsAny())).Returns(() => + userRepositoryMock.Setup(repo => repo.UpdateAsync(It.IsAny())).ReturnsAsync(() => { return UserMock.GetGrantee(); }); - userRepositoryMock.Setup(repo => repo.Find(It.IsAny>>())).Returns(() => + userRepositoryMock.Setup(repo => repo.FindAsync(It.IsAny>>())).ReturnsAsync(() => { 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 = "" @@ -177,10 +179,10 @@ public void 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" @@ -193,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" @@ -206,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" 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 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/0 - CancelAbandonedDonations.cs b/ShareBook/Sharebook.Jobs/Jobs/0 - CancelAbandonedDonations.cs index 10c3a7d2..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; @@ -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/1 - ChooseDateReminder.cs b/ShareBook/Sharebook.Jobs/Jobs/1 - ChooseDateReminder.cs index 97230e09..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.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 9706b546..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,13 +42,13 @@ public LateDonationNotification(IJobHistoryRepository jobHistoryRepo, _emailTemplate = emailTemplate; _configuration = configuration; - maxLateDonationDays = int.Parse(_configuration["SharebookSettings:MaxLateDonationDays"]); + maxLateDonationDays = int.Parse(_configuration[ConfigMaxLateDonationDaysKey]); } public override async Task WorkAsync() { - var status = _bookService.GetStats(); + var status = await _bookService.GetStatsAsync(); var booksLate = await _bookService.GetBooksChooseDateIsLateAsync(); var donators = GetDistinctDonators(booksLate); @@ -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.SendToAdmins(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.Send(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.Send(donator.Email, donator.Name, html, emailSubject, copyAdmins: false, highPriority: true); + await _emailService.SendAsync(donator.Email, donator.Name, html, EmailDonatorSoftSubject, copyAdmins: false, highPriority: true); } #endregion diff --git a/ShareBook/Sharebook.Jobs/Jobs/3 - RemoveBookFromShowcase.cs b/ShareBook/Sharebook.Jobs/Jobs/3 - RemoveBookFromShowcase.cs index e1ded63c..f1702ab1 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."); @@ -66,8 +65,7 @@ public override async Task WorkAsync() await SendEmailAsync(book); } - // TODO: Migrate to async - _bookService.Update(book); + await _bookService.UpdateAsync(book); } return new JobHistory() @@ -97,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 97484556..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) @@ -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); @@ -89,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() @@ -117,7 +116,7 @@ private int GetEmailMaxDestinationsPerQueueMessage() } private async Task GetEmailTemplateAsync(Guid bookId){ - var book = _bookService.Find(bookId); + var book = await _bookService.FindAsync(bookId); var vm = new { 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() 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); } }