From 1041d0ff4c3db2bb64af499197878d1d2325a457 Mon Sep 17 00:00:00 2001 From: Diego Carlito Date: Fri, 8 Dec 2023 08:16:56 -0300 Subject: [PATCH 01/12] =?UTF-8?q?Implementa=C3=A7=C3=A3o=20de=20atualiza?= =?UTF-8?q?=C3=A7=C3=A3o=20de=20tokens?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/services/auth.service.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/app/services/auth.service.ts b/src/app/services/auth.service.ts index c91004b4..55269e4b 100644 --- a/src/app/services/auth.service.ts +++ b/src/app/services/auth.service.ts @@ -45,7 +45,11 @@ export class AuthService { const token = localStorage.getItem('token'); return !!token; } - + + refreshToken(): Observable { + return this.http.post(`${this.usersAPIURL}/auth/refresh`, null); + } + logout(): void { localStorage.removeItem('token'); this.router.navigate(['/login']); From f01c238548e5e7f24ea9de2d77af9ec4c1e7564e Mon Sep 17 00:00:00 2001 From: Diego Carlito Date: Fri, 8 Dec 2023 08:23:49 -0300 Subject: [PATCH 02/12] =?UTF-8?q?Adicionando=20m=C3=A9todo=20para=20renova?= =?UTF-8?q?=C3=A7=C3=A3o=20do=20token?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/pages/profile/profile.component.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/app/pages/profile/profile.component.ts b/src/app/pages/profile/profile.component.ts index f147e0a5..f4d33636 100644 --- a/src/app/pages/profile/profile.component.ts +++ b/src/app/pages/profile/profile.component.ts @@ -91,6 +91,21 @@ export class ProfileComponent { }); } + renewToken() { + this.authService.refreshToken().subscribe({ + next: (response) => { + if (response && response.access_token) { + localStorage.setItem('token', response.access_token); + this.getUser(); + } + }, + error: (error: ErrorResponseType) => { + console.error('Failed to refresh token:', error); + this.authService.logout(); + } + }); + } + navigatorEdit(): void { this.router.navigate([`/editUser/${this.user.id}`]); } From b52840c67b15f38e9317ac3e0a7e4cdf9b230259 Mon Sep 17 00:00:00 2001 From: Diego Carlito Date: Fri, 8 Dec 2023 08:26:02 -0300 Subject: [PATCH 03/12] =?UTF-8?q?Popup=20para=20renova=C3=A7=C3=A3o=20do?= =?UTF-8?q?=20token?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/pages/profile/profile.component.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/app/pages/profile/profile.component.ts b/src/app/pages/profile/profile.component.ts index f4d33636..b544c3a6 100644 --- a/src/app/pages/profile/profile.component.ts +++ b/src/app/pages/profile/profile.component.ts @@ -91,6 +91,21 @@ export class ProfileComponent { }); } + showRenewTokenDialog() { + this.confirmationService.confirm({ + message: 'Deseja se manter logado?', + header: 'Confirmação', + key: 'myDialog', + icon: 'pi pi-exclamation-triangle', + accept: () => { + this.renewToken(); + }, + reject: () => { + this.authService.logout(); + }, + }); + } + renewToken() { this.authService.refreshToken().subscribe({ next: (response) => { From b563df717c7a837e9f0a8caa78d4ce85725a728c Mon Sep 17 00:00:00 2001 From: Diego Carlito Date: Fri, 8 Dec 2023 08:30:12 -0300 Subject: [PATCH 04/12] =?UTF-8?q?Adicionando=20um=20temporizador=20para=20?= =?UTF-8?q?o=20Popup=20de=20renova=C3=A7=C3=A3o=20do=20token?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/pages/profile/profile.component.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/app/pages/profile/profile.component.ts b/src/app/pages/profile/profile.component.ts index b544c3a6..a0cd10c3 100644 --- a/src/app/pages/profile/profile.component.ts +++ b/src/app/pages/profile/profile.component.ts @@ -7,6 +7,7 @@ import { AlertService } from 'src/app/services/alert.service'; import { ConfirmationService, MessageService } from 'primeng/api'; import { AuthService } from 'src/app/services/auth.service'; import { HttpErrorResponse } from '@angular/common/http'; +import { take, timer } from 'rxjs'; type ErrorResponseType = HttpErrorResponse; @@ -32,6 +33,11 @@ export class ProfileComponent { ngOnInit(): void { this.setUserIdFromToken(localStorage.getItem('token') as string); this.getUser(); + timer(15 * 60 * 1000) + .pipe(take(1)) + .subscribe(() => { + this.showRenewTokenDialog(); + }); } setUserIdFromToken(token: string) { From 50ebdc914cb44c44bd14460753d42fb094ac6f15 Mon Sep 17 00:00:00 2001 From: Diego Carlito Date: Fri, 8 Dec 2023 12:37:25 -0300 Subject: [PATCH 05/12] =?UTF-8?q?Melhorando=20o=20c=C3=B3digo=20para=20fic?= =?UTF-8?q?ar=20mais=20conciso=20e=20leg=C3=ADvel?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/pages/profile/profile.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/pages/profile/profile.component.ts b/src/app/pages/profile/profile.component.ts index a0cd10c3..a63526b7 100644 --- a/src/app/pages/profile/profile.component.ts +++ b/src/app/pages/profile/profile.component.ts @@ -115,7 +115,7 @@ export class ProfileComponent { renewToken() { this.authService.refreshToken().subscribe({ next: (response) => { - if (response && response.access_token) { + if (response?.access_token) { localStorage.setItem('token', response.access_token); this.getUser(); } From d86494fc3896c8198a88890344026fac80bec63c Mon Sep 17 00:00:00 2001 From: Diego Carlito Date: Fri, 8 Dec 2023 12:49:16 -0300 Subject: [PATCH 06/12] =?UTF-8?q?Teste=20para=20a=20fun=C3=A7=C3=A3o=20ref?= =?UTF-8?q?reshToken?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/services/auth.service.spec.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/app/services/auth.service.spec.ts b/src/app/services/auth.service.spec.ts index f5736b2e..29599618 100644 --- a/src/app/services/auth.service.spec.ts +++ b/src/app/services/auth.service.spec.ts @@ -118,6 +118,18 @@ describe('AuthService', () => { req.flush(userResponse); }); + it('should refresh token', () => { + const dummyResponse = { access_token: 'dummyToken' }; + + service.refreshToken().subscribe(res => { + expect(res).toEqual(dummyResponse); + }); + + const req = httpMock.expectOne(`${service.usersAPIURL}/auth/refresh`); + expect(req.request.method).toBe('POST'); + req.flush(dummyResponse); + }); + it('should logout', () => { localStorage.setItem('token', 'testtoken'); service.logout(); From 1a319f967cbc0c2937562fd58354a981cdf43e20 Mon Sep 17 00:00:00 2001 From: Diego Carlito Date: Fri, 8 Dec 2023 12:57:18 -0300 Subject: [PATCH 07/12] Teste para renewToken --- src/app/pages/profile/profile.component.spec.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/app/pages/profile/profile.component.spec.ts b/src/app/pages/profile/profile.component.spec.ts index 8f879141..77bc8814 100644 --- a/src/app/pages/profile/profile.component.spec.ts +++ b/src/app/pages/profile/profile.component.spec.ts @@ -125,6 +125,18 @@ describe('ProfileComponent', () => { expect(mySpy).toHaveBeenCalled(); }); + it('should renew token', () => { + spyOn(authService, 'refreshToken').and.returnValue(of({ access_token: 'newToken' })); + spyOn(localStorage, 'setItem'); + spyOn(component, 'getUser'); + + component.renewToken(); + + expect(authService.refreshToken).toHaveBeenCalled(); + expect(localStorage.setItem).toHaveBeenCalledWith('token', 'newToken'); + expect(component.getUser).toHaveBeenCalled(); + }); + it('should call navigatorEdit when editUser is clicked', () => { spyOn(component, 'navigatorEdit').and.callThrough(); const navigateSpy = spyOn(router, 'navigate'); From f68fba68f2d377d6bea727538f82c7882b490489 Mon Sep 17 00:00:00 2001 From: Diego Carlito Date: Fri, 8 Dec 2023 13:09:12 -0300 Subject: [PATCH 08/12] =?UTF-8?q?Tirando=20partes=20do=20c=C3=B3digo=20que?= =?UTF-8?q?=20n=C3=A3o=20est=C3=A3o=20sendo=20usadas?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/pages/profile/profile.component.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/app/pages/profile/profile.component.ts b/src/app/pages/profile/profile.component.ts index a63526b7..520a564e 100644 --- a/src/app/pages/profile/profile.component.ts +++ b/src/app/pages/profile/profile.component.ts @@ -117,7 +117,6 @@ export class ProfileComponent { next: (response) => { if (response?.access_token) { localStorage.setItem('token', response.access_token); - this.getUser(); } }, error: (error: ErrorResponseType) => { From 49edd16b425da74a7262528efdcabb561cf8ff9f Mon Sep 17 00:00:00 2001 From: Diego Carlito Date: Fri, 8 Dec 2023 13:10:25 -0300 Subject: [PATCH 09/12] =?UTF-8?q?Melhorando=20a=20l=C3=B3gica=20do=20teste?= =?UTF-8?q?=20de=20renewToken?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/pages/profile/profile.component.spec.ts | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/app/pages/profile/profile.component.spec.ts b/src/app/pages/profile/profile.component.spec.ts index 77bc8814..a2ea785e 100644 --- a/src/app/pages/profile/profile.component.spec.ts +++ b/src/app/pages/profile/profile.component.spec.ts @@ -125,16 +125,13 @@ describe('ProfileComponent', () => { expect(mySpy).toHaveBeenCalled(); }); - it('should renew token', () => { - spyOn(authService, 'refreshToken').and.returnValue(of({ access_token: 'newToken' })); - spyOn(localStorage, 'setItem'); - spyOn(component, 'getUser'); + it('should call refreshToken and set token in localStorage', () => { + spyOn(authService, 'refreshToken').and.returnValue(of({ access_token: 'new_access_token' })); component.renewToken(); expect(authService.refreshToken).toHaveBeenCalled(); - expect(localStorage.setItem).toHaveBeenCalledWith('token', 'newToken'); - expect(component.getUser).toHaveBeenCalled(); + expect(localStorage.getItem('token')).toEqual('new_access_token'); }); it('should call navigatorEdit when editUser is clicked', () => { From 932210e198b9a04f0406ddad45f5313713cb167d Mon Sep 17 00:00:00 2001 From: Marcos Castilhos <221008300@aluno.unb.br> Date: Fri, 8 Dec 2023 18:33:36 -0300 Subject: [PATCH 10/12] adiciona refreshToken ao authServiceMock --- src/app/pages/profile/profile.component.spec.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/app/pages/profile/profile.component.spec.ts b/src/app/pages/profile/profile.component.spec.ts index a2ea785e..59ffc550 100644 --- a/src/app/pages/profile/profile.component.spec.ts +++ b/src/app/pages/profile/profile.component.spec.ts @@ -38,6 +38,9 @@ class AlertServiceMock { class AuthServiceMock { logout() { } + refreshToken() { + return of({ success: true }); + } } class ConfirmationServiceMock { @@ -133,6 +136,7 @@ describe('ProfileComponent', () => { expect(authService.refreshToken).toHaveBeenCalled(); expect(localStorage.getItem('token')).toEqual('new_access_token'); }); + it('should call navigatorEdit when editUser is clicked', () => { spyOn(component, 'navigatorEdit').and.callThrough(); From b5430740dbda663f7e3080d470a8b254417a052e Mon Sep 17 00:00:00 2001 From: Marcos Castilhos <221008300@aluno.unb.br> Date: Fri, 8 Dec 2023 18:49:00 -0300 Subject: [PATCH 11/12] Adiciona caso de erro para refreshToken --- src/app/pages/profile/profile.component.spec.ts | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/app/pages/profile/profile.component.spec.ts b/src/app/pages/profile/profile.component.spec.ts index 59ffc550..111128a0 100644 --- a/src/app/pages/profile/profile.component.spec.ts +++ b/src/app/pages/profile/profile.component.spec.ts @@ -38,9 +38,7 @@ class AlertServiceMock { class AuthServiceMock { logout() { } - refreshToken() { - return of({ success: true }); - } + refreshToken() { } } class ConfirmationServiceMock { @@ -137,6 +135,15 @@ describe('ProfileComponent', () => { expect(localStorage.getItem('token')).toEqual('new_access_token'); }); + it('should handle error when renewing token', () => { + spyOn(authService, 'refreshToken').and.returnValue(throwError('error')); + spyOn(console, 'error'); + + component.renewToken(); + + expect(authService.refreshToken).toHaveBeenCalled(); + expect(console.error).toHaveBeenCalledWith('Failed to refresh token:', 'error'); + }); it('should call navigatorEdit when editUser is clicked', () => { spyOn(component, 'navigatorEdit').and.callThrough(); From 41029a8c400ff2cb1e153f6c1770e2072d10aa53 Mon Sep 17 00:00:00 2001 From: Marcos Castilhos <221008300@aluno.unb.br> Date: Fri, 8 Dec 2023 18:59:56 -0300 Subject: [PATCH 12/12] Adiciona teste para showRenewTokenDialog --- .../pages/profile/profile.component.spec.ts | 27 ++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/src/app/pages/profile/profile.component.spec.ts b/src/app/pages/profile/profile.component.spec.ts index 111128a0..38def172 100644 --- a/src/app/pages/profile/profile.component.spec.ts +++ b/src/app/pages/profile/profile.component.spec.ts @@ -39,6 +39,7 @@ class AlertServiceMock { class AuthServiceMock { logout() { } refreshToken() { } + showRenewTokenDialog() { } } class ConfirmationServiceMock { @@ -134,7 +135,7 @@ describe('ProfileComponent', () => { expect(authService.refreshToken).toHaveBeenCalled(); expect(localStorage.getItem('token')).toEqual('new_access_token'); }); - + it('should handle error when renewing token', () => { spyOn(authService, 'refreshToken').and.returnValue(throwError('error')); spyOn(console, 'error'); @@ -144,6 +145,30 @@ describe('ProfileComponent', () => { expect(authService.refreshToken).toHaveBeenCalled(); expect(console.error).toHaveBeenCalledWith('Failed to refresh token:', 'error'); }); + it('should show renew token dialog', () => { + const confirmSpy = spyOn(confirmationService, 'confirm').and.callFake((params: any) => { + params.accept(); + params.reject(); + + // Return a mock ConfirmationService instance + return {} as ConfirmationService; + }); + const renewTokenSpy = spyOn(component, 'renewToken'); + const logoutSpy = spyOn(authService, 'logout'); + + component.showRenewTokenDialog(); + + expect(confirmSpy).toHaveBeenCalledWith({ + message: 'Deseja se manter logado?', + header: 'Confirmação', + key: 'myDialog', + icon: 'pi pi-exclamation-triangle', + accept: jasmine.any(Function), + reject: jasmine.any(Function), + }); + expect(renewTokenSpy).toHaveBeenCalled(); + expect(logoutSpy).toHaveBeenCalled(); + }); it('should call navigatorEdit when editUser is clicked', () => { spyOn(component, 'navigatorEdit').and.callThrough();