Skip to content

Commit 2899c6a

Browse files
committed
feat: TT-453 add Authentication with google locally
1 parent 3e32610 commit 2899c6a

26 files changed

+351
-41
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
"@types/datatables.net-buttons": "1.4.3",
3636
"angular-calendar": "0.28.26",
3737
"angular-datatables": "9.0.2",
38+
"angularx-social-login": "^3.5.7",
3839
"bootstrap": "4.4.1",
3940
"datatables.net": "1.10.22",
4041
"datatables.net-buttons": "1.6.2",

src/app/app.module.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,8 @@ import { CalendarComponent } from './modules/time-entries/components/calendar/ca
8787
import { DropdownComponent } from './modules/shared/components/dropdown/dropdown.component';
8888
import { NgSelectModule } from '@ng-select/ng-select';
8989
import { DarkModeComponent } from './modules/shared/components/dark-mode/dark-mode.component';
90+
import { SocialLoginModule, SocialAuthServiceConfig } from 'angularx-social-login';
91+
import { GoogleLoginProvider } from 'angularx-social-login';
9092

9193
const maskConfig: Partial<IConfig> = {
9294
validation: false,
@@ -184,7 +186,8 @@ const maskConfig: Partial<IConfig> = {
184186
provide: DateAdapter,
185187
useFactory: adapterFactory,
186188
}),
187-
NgSelectModule
189+
NgSelectModule,
190+
SocialLoginModule
188191
],
189192
providers: [
190193
{
@@ -194,6 +197,20 @@ const maskConfig: Partial<IConfig> = {
194197
},
195198
DatePipe,
196199
CookieService,
200+
{
201+
provide: 'SocialAuthServiceConfig',
202+
useValue: {
203+
autoLogin: false,
204+
providers: [
205+
{
206+
id: GoogleLoginProvider.PROVIDER_ID,
207+
provider: new GoogleLoginProvider(
208+
'711486856840-f8u9pdmkk44nmkb0c9lbsjvolp2hulur.apps.googleusercontent.com'
209+
)
210+
}
211+
]
212+
} as SocialAuthServiceConfig,
213+
}
197214
],
198215
bootstrap: [AppComponent],
199216
})

src/app/guards/login-guard/login.guard.spec.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ import { Router } from '@angular/router';
44

55
import { AzureAdB2CService } from '../../modules/login/services/azure.ad.b2c.service';
66
import { LoginGuard } from './login.guard';
7+
import { LoginService } from '../../modules/login/services/login.service';
8+
import { HttpClientTestingModule } from '@angular/common/http/testing';
9+
import { SocialAuthService } from 'angularx-social-login';
710

811

912
describe('LoginGuard', () => {
@@ -15,29 +18,42 @@ describe('LoginGuard', () => {
1518
return true;
1619
}
1720
};
21+
let loginService: LoginService;
22+
const loginServiceStub = {
23+
isLogin() {
24+
return true;
25+
}
26+
};
27+
const socialAuthServiceStub = jasmine.createSpyObj('SocialAuthService', ['authState']);
1828
beforeEach(() => {
1929
TestBed.configureTestingModule({
20-
imports: [ RouterTestingModule ],
30+
imports: [ RouterTestingModule, HttpClientTestingModule ],
2131
providers: [
2232
{ providers: AzureAdB2CService, useValue: azureAdB2CServiceStub},
33+
{ providers: LoginService, useValue: loginServiceStub},
34+
{ provide: SocialAuthService, useValue: socialAuthServiceStub }
2335
]
2436
});
2537
loginGuard = TestBed.inject(LoginGuard);
2638
azureAdB2CService = TestBed.inject(AzureAdB2CService);
39+
loginService = TestBed.inject(LoginService);
2740
});
2841

2942
it('should be created', () => {
3043
expect(loginGuard).toBeTruthy();
3144
});
3245

3346
it('can activate the route when user is logged-in', () => {
47+
loginGuard.isProduction = true;
3448
spyOn(azureAdB2CService, 'isLogin').and.returnValue(true);
3549
const canActivate = loginGuard.canActivate();
3650
expect(azureAdB2CService.isLogin).toHaveBeenCalled();
3751
expect(canActivate).toEqual(true);
3852
});
3953

54+
4055
it('can not active the route and is redirected to login if user is not logged-in', inject([Router], (router: Router) => {
56+
loginGuard.isProduction = true;
4157
spyOn(azureAdB2CService, 'isLogin').and.returnValue(false);
4258
spyOn(router, 'navigate').and.stub();
4359
const canActivate = loginGuard.canActivate();
Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,37 @@
11
import { Injectable } from '@angular/core';
22
import { Router, CanActivate } from '@angular/router';
33
import { AzureAdB2CService } from '../../modules/login/services/azure.ad.b2c.service';
4+
import { LoginService } from '../../modules/login/services/login.service';
5+
import { environment } from 'src/environments/environment';
46

57
@Injectable({
6-
providedIn: 'root'
8+
providedIn: 'root',
79
})
810
export class LoginGuard implements CanActivate {
9-
10-
constructor(private azureAdB2CService: AzureAdB2CService, private router: Router) { }
11+
isProduction = environment.production;
12+
constructor(
13+
private azureAdB2CService: AzureAdB2CService,
14+
private router: Router,
15+
private loginService: LoginService
16+
) {}
1117

1218
canActivate() {
13-
if (this.azureAdB2CService.isLogin()) {
19+
if (this.isProduction) {
20+
if (this.azureAdB2CService.isLogin()) {
1421
this.azureAdB2CService.setCookies();
1522
return true;
23+
} else {
24+
this.router.navigate(['login']);
25+
return false;
26+
}
1627
} else {
28+
if (this.loginService.isLogin()) {
29+
this.loginService.setCookies();
30+
return true;
31+
} else {
1732
this.router.navigate(['login']);
1833
return false;
34+
}
1935
}
2036
}
2137
}

src/app/modules/home/home.component.spec.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { MockStore, provideMockStore } from '@ngrx/store/testing';
33
import { AzureAdB2CService } from '../login/services/azure.ad.b2c.service';
44
import { LoadUser } from '../user/store/user.actions';
55
import { HomeComponent } from './home.component';
6+
import { LoginService } from '../login/services/login.service';
67

78
describe('HomeComponent', () => {
89
let component: HomeComponent;
@@ -13,6 +14,9 @@ describe('HomeComponent', () => {
1314
const azureB2CServiceStub = {
1415
getUserId: () => 'user_id',
1516
};
17+
const loginServiceStub = {
18+
getUserId: () => 'user_id',
19+
};
1620

1721
beforeEach(
1822
waitForAsync(() => {
@@ -21,6 +25,7 @@ describe('HomeComponent', () => {
2125
providers: [
2226
provideMockStore({ initialState }),
2327
{ provide: AzureAdB2CService, useValue: azureB2CServiceStub },
28+
{ provide: LoginService, useValue: loginServiceStub },
2429
],
2530
}).compileComponents();
2631
})
@@ -30,7 +35,6 @@ describe('HomeComponent', () => {
3035
fixture = TestBed.createComponent(HomeComponent);
3136
azureAdB2CService = TestBed.inject(AzureAdB2CService);
3237
store = TestBed.inject(MockStore);
33-
3438
component = fixture.componentInstance;
3539
fixture.detectChanges();
3640
store.setState(initialState);
@@ -41,6 +45,7 @@ describe('HomeComponent', () => {
4145
});
4246

4347
it('onInit, LoadUser action is dispatched', () => {
48+
component.isProduction = true;
4449
const userId = 'user_id';
4550
spyOn(azureAdB2CService, 'getUserId').and.returnValue(userId);
4651
spyOn(store, 'dispatch');
Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,25 @@
11
import { Component, OnInit } from '@angular/core';
22
import { Store } from '@ngrx/store';
33
import { LoadUser } from 'src/app/modules/user/store/user.actions';
4+
import { environment } from 'src/environments/environment';
45
import { AzureAdB2CService } from '../login/services/azure.ad.b2c.service';
6+
import { LoginService } from '../login/services/login.service';
57

68
@Component({
79
selector: 'app-home',
810
templateUrl: './home.component.html',
911
styleUrls: ['./home.component.scss'],
1012
})
1113
export class HomeComponent implements OnInit {
12-
14+
isProduction = environment.production;
1315
constructor(
1416
private azureAdB2CService: AzureAdB2CService,
17+
private loginService: LoginService,
1518
private store: Store
1619
) { }
1720

1821
ngOnInit(): void {
19-
const userId = this.azureAdB2CService.getUserId();
22+
const userId = this.isProduction ? this.azureAdB2CService.getUserId() : this.loginService.getUserId();
2023
this.store.dispatch(new LoadUser(userId));
2124
}
2225
}

src/app/modules/login/login.component.html

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,16 @@
77
<h3>Please log in</h3>
88
</div>
99

10-
<div class="login-controls">
10+
<div class="login-controls" *ngIf="!isDevelopment">
1111
<button (click)="login()" class="btn btn-primary">login</button>
1212
</div>
1313

14+
<div class="container" style="max-width: 550px" *ngIf="isDevelopment">
15+
<div >
16+
<div class="login-controls">
17+
<button type="button" (click)="loginWithGoogle()" class="btn btn-primary">Login with Google</button>
18+
</div>
19+
</div>
20+
</div>
21+
1422
</div>

src/app/modules/login/login.component.spec.ts

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,15 @@ import { of } from 'rxjs';
55
import { LoginComponent } from './login.component';
66
import { Router } from '@angular/router';
77
import { FeatureToggleCookiesService } from '../shared/feature-toggles/feature-toggle-cookies/feature-toggle-cookies.service';
8+
import { LoginService } from './services/login.service';
9+
import { HttpClientTestingModule } from '@angular/common/http/testing';
10+
import { SocialAuthService } from 'angularx-social-login';
811

912
describe('LoginComponent', () => {
1013
let component: LoginComponent;
1114
let fixture: ComponentFixture<LoginComponent>;
1215
let azureAdB2CService: AzureAdB2CService;
16+
let loginService: LoginService;
1317
let featureToggleCookiesService: FeatureToggleCookiesService;
1418

1519
const azureAdB2CServiceStub = {
@@ -23,29 +27,46 @@ describe('LoginComponent', () => {
2327
}
2428
};
2529

30+
const loginServiceStub = {
31+
isLogin() {
32+
return true;
33+
},
34+
signIn() {
35+
return of();
36+
},
37+
setCookies() {
38+
}
39+
};
40+
2641
const featureToggleCookiesServiceStub = {
2742
setCookies() {
2843
return null;
2944
}
3045
};
3146

47+
const socialAuthServiceStub = jasmine.createSpyObj('SocialAuthService', ['authState']);
3248
beforeEach(waitForAsync(() => {
3349
TestBed.configureTestingModule({
34-
imports: [ RouterTestingModule ],
50+
imports: [ RouterTestingModule, HttpClientTestingModule],
3551
declarations: [ LoginComponent ],
3652
providers: [
3753
{ providers: AzureAdB2CService, useValue: azureAdB2CServiceStub},
38-
{ providers: FeatureToggleCookiesService, useValue: featureToggleCookiesServiceStub}
54+
{ providers: FeatureToggleCookiesService, useValue: featureToggleCookiesServiceStub},
55+
{ providers: LoginService, useValue: loginServiceStub},
56+
{ provide: SocialAuthService, useValue: socialAuthServiceStub }
3957
]
4058
})
4159
.compileComponents();
4260
}));
4361

4462
beforeEach(() => {
63+
socialAuthServiceStub.authState = of(null);
4564
fixture = TestBed.createComponent(LoginComponent);
4665
component = fixture.componentInstance;
66+
component.isDevelopment = false;
4767
fixture.detectChanges();
4868
azureAdB2CService = TestBed.inject(AzureAdB2CService);
69+
loginService = TestBed.inject(LoginService);
4970
featureToggleCookiesService = TestBed.inject(FeatureToggleCookiesService);
5071
});
5172

src/app/modules/login/login.component.ts

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,41 @@ import { AzureAdB2CService } from './services/azure.ad.b2c.service';
33
import { Router } from '@angular/router';
44
import { FeatureToggleCookiesService } from '../shared/feature-toggles/feature-toggle-cookies/feature-toggle-cookies.service';
55

6+
import { SocialAuthService, SocialUser } from 'angularx-social-login';
7+
import { environment } from 'src/environments/environment';
8+
import { LoginService } from './services/login.service';
69
@Component({
710
selector: 'app-login',
811
templateUrl: './login.component.html',
9-
styleUrls: ['./login.component.scss']
12+
styleUrls: ['./login.component.scss'],
1013
})
11-
1214
export class LoginComponent {
15+
socialUser: SocialUser;
16+
isDevelopment = true;
1317

1418
constructor(
1519
private azureAdB2CService: AzureAdB2CService,
1620
private router: Router,
17-
private featureToggleCookiesService: FeatureToggleCookiesService
21+
private featureToggleCookiesService: FeatureToggleCookiesService,
22+
private socialAuthService: SocialAuthService,
23+
private loginService?: LoginService
1824
) {}
1925

26+
OnInit() {
27+
this.isDevelopment = !environment.production;
28+
this.socialAuthService.authState.subscribe((user) => {
29+
if (user != null) {
30+
this.featureToggleCookiesService.setCookies();
31+
this.loginService.setLocalStorage('idToken', user.idToken);
32+
this.loginService.getUser(user.idToken).subscribe((response) => {
33+
this.loginService.setCookies();
34+
this.loginService.setLocalStorage('user2', JSON.stringify(response));
35+
this.router.navigate(['']);
36+
});
37+
}
38+
});
39+
}
40+
2041
login(): void {
2142
if (this.azureAdB2CService.isLogin()) {
2243
this.router.navigate(['']);
@@ -29,4 +50,11 @@ export class LoginComponent {
2950
}
3051
}
3152

53+
loginWithGoogle(): void {
54+
this.loginService.signIn();
55+
}
56+
57+
logOut(): void {
58+
this.loginService.logout();
59+
}
3260
}

0 commit comments

Comments
 (0)