Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NXP-32714: add signout butn #65

Merged
merged 4 commits into from
Jul 4, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/utest.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -66,4 +66,4 @@ jobs:
- name: Unit tests
working-directory: nuxeo-admin-console-web/angular-app
run: |
xvfb-run --auto-servernum --server-args="-screen 0 1024x768x24" npm test
xvfb-run --auto-servernum --server-args="-screen 0 1024x768x24" npm test
12 changes: 0 additions & 12 deletions nuxeo-admin-console-package/package.json

This file was deleted.

4 changes: 3 additions & 1 deletion nuxeo-admin-console-web/angular-app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"watch": "ng build --watch --configuration development",
"test": "ng test --code-coverage --watch=false",
"lint": "ng lint",
"clean":"npm cache clean --force",
"clean": "npm cache clean --force",
"prepare": "husky"
},
"dependencies": {
Expand All @@ -28,6 +28,8 @@
"@ngrx/router-store": "^16.0.0",
"@ngrx/store": "^16.0.0",
"@ngrx/store-devtools": "^16.0.0",
"angular": "^1.8.3",
"angular-material": "^1.2.5",
"angular-oauth2-oidc": "^15.0.1",
"hammerjs": "^2.0.8",
"rxjs": "~7.8.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import { PersistenceService } from "./shared/services/persistence.service";
import { WarningComponent } from "./features/warning/warning.component";
import { CommonService } from "./shared/services/common.service";
import { EventEmitter } from "@angular/core";
import { provideMockStore } from '@ngrx/store/testing';
import { StoreModule } from '@ngrx/store';

describe("AppComponent", () => {
let component: AppComponent;
Expand All @@ -32,7 +34,7 @@ describe("AppComponent", () => {
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [AppComponent, BaseLayoutComponent],
imports: [CommonModule, MatDialogModule],
imports: [CommonModule, MatDialogModule, StoreModule.forRoot(provideMockStore)],
providers: [
{ provide: ComponentFixtureAutoDetect, useValue: true },
{ provide: PersistenceService, useClass: persistenceServiceStub },
Expand All @@ -53,6 +55,7 @@ describe("AppComponent", () => {
spyOn(component.dialogService, "open");
});
it("should open the warning dialog if warning preference is not set", () => {
if (component?.currentUser) {
spyOn(component.persistenceService, "get").and.returnValue(null);
const loadAppSubscriptionSpy = spyOn(
component.commonService.loadApp,
Expand All @@ -67,29 +70,36 @@ describe("AppComponent", () => {
}
);
expect(loadAppSubscriptionSpy).toHaveBeenCalled();
}
});

it("should not open the warning dialog if warning preference is set", () => {
if (component?.currentUser) {
spyOn(component.persistenceService, "get").and.returnValue("true");
component.ngOnInit();
expect(component.persistenceService.get).toHaveBeenCalled();
expect(component.dialogService.open).not.toHaveBeenCalled();
expect(component.loadApp).toEqual(true);
}
});
});

it("should set loadApp to true or false based on the value received from the service subscription", () => {
if (component?.currentUser) {
component.ngOnInit();
component.commonService.loadApp.emit(true);
expect(component.loadApp).toBe(true);
component.ngOnInit();
component.commonService.loadApp.emit(false);
expect(component.loadApp).toBe(false);
}
});

it("should remove theloadAppSubscription when component is destroyed", () => {
if (component?.currentUser) {
spyOn(component.loadAppSubscription, "unsubscribe");
component.ngOnDestroy();
expect(component.loadAppSubscription.unsubscribe).toHaveBeenCalled();
}
});
});
49 changes: 33 additions & 16 deletions nuxeo-admin-console-web/angular-app/src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@ import { NuxeoJSClientService } from './shared/services/nuxeo-js-client.service'
import { Component, OnDestroy, OnInit } from "@angular/core";
import { MatDialog } from "@angular/material/dialog";
import { PersistenceService } from "./shared/services/persistence.service";
import { Subscription } from "rxjs";
import { Subscription, Observable } from "rxjs";
import { CommonService } from "./shared/services/common.service";
import { WarningComponent } from "./features/warning/warning.component";
import { Store, select } from "@ngrx/store";
import { authActions } from "./auth/store/actions";
import { AuthStateInterface } from "./auth/types/authState.interface";
import { UserInterface } from './shared/types/user.interface';

@Component({
selector: "app",
Expand All @@ -14,30 +18,43 @@ import { WarningComponent } from "./features/warning/warning.component";
export class AppComponent implements OnInit, OnDestroy {
loadApp = false;
loadAppSubscription = new Subscription();
currentUser$: Observable<UserInterface | null | undefined>;
currentUserSubscription: Subscription = new Subscription();
currentUser: UserInterface | null | undefined = undefined;
constructor(
public dialogService: MatDialog,
public persistenceService: PersistenceService,
public commonService: CommonService,
private nuxeoJsClientService: NuxeoJSClientService
) {}
private nuxeoJsClientService: NuxeoJSClientService,
private store: Store<{ auth: AuthStateInterface }>
) {
this.currentUser$ = this.store.pipe(select((state: { auth: AuthStateInterface }) => state.auth.currentUser));
rakeshkumar1019 marked this conversation as resolved.
Show resolved Hide resolved
}

ngOnInit(): void {
this.nuxeoJsClientService.initiateJSClient();
const doNotWarn = !!this.persistenceService.get("doNotWarn");
if (!doNotWarn) {
this.dialogService.open(WarningComponent, {
disableClose: true,
});
this.loadAppSubscription = this.commonService.loadApp.subscribe(
(load) => {
this.loadApp = load;
this.currentUserSubscription = this.currentUser$.subscribe(user => {
this.currentUser = user;
if (this.currentUser) {
const preferenceKey = `doNotWarn-${this.currentUser.id}`;
const doNotWarn = !!this.persistenceService.get(preferenceKey);
if (!doNotWarn) {
this.dialogService.open(WarningComponent, {
disableClose: true,
});
this.loadAppSubscription = this.commonService.loadApp.subscribe(load => {
this.loadApp = load;
});
} else {
this.loadApp = true;
}
);
} else {
this.loadApp = true;
}
}
});

this.store.dispatch(authActions.getCurrentUser());
}
ngOnDestroy(): void {
this.loadAppSubscription.unsubscribe();
this.currentUserSubscription.unsubscribe();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,48 @@ import { HttpClient } from "@angular/common/http";
import { map, Observable } from "rxjs";
import { environment } from "../../../environments/environment";
import { UserInterface } from "../../shared/types/user.interface";
import { AuthResponseInterface } from "../types/authResponse.interface";
import { AuthUserResponseInterface } from "../types/authResponse.interface";
import { HylandSSORequestInterface } from "../types/hylandSSORequest.interface";
import { NuxeoJSClientService } from "../../shared/services/nuxeo-js-client.service";

@Injectable({
providedIn: "root",
})
export class AuthService {
constructor(private http: HttpClient) {}
constructor(private http: HttpClient, private nuxeoJsClientService: NuxeoJSClientService) { }

getUser(response: AuthResponseInterface): UserInterface {
return response.user;
}

getCurrentUser(): Observable<UserInterface> {
const url = environment.apiUrl + "/user.json";
return this.http.get<AuthResponseInterface>(url).pipe(map(this.getUser));
const url = `${this.nuxeoJsClientService.getApiUrl()}me`;
return this.http.get<AuthUserResponseInterface>(url).pipe(
map(response => this.getUser(response))
);
}

getUser(response: AuthUserResponseInterface): UserInterface {
return {
rakeshkumar1019 marked this conversation as resolved.
Show resolved Hide resolved
id: response.id,
properties: {
firstName: response.properties.firstName,
lastName: response.properties.lastName,
email: response.properties.email,
username: response.properties.username
}
};
}

sso(data: HylandSSORequestInterface): Observable<UserInterface> {
const url = environment.apiUrl + "/users/sso";
return this.http
.post<AuthResponseInterface>(url, data)
.post<AuthUserResponseInterface>(url, data)
.pipe(map(this.getUser));
}
signOut(): Observable<void> {
const url = `${this.nuxeoJsClientService.getBaseUrl()}logout`;
return this.http.get<void>(url, {});
}

}



Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,8 @@ export const authActions = createActionGroup({
"Get current user": emptyProps(),
"Get current user success": props<{ currentUser: UserInterface }>(),
"Get current user failure": emptyProps(),
"Sign out": emptyProps(),
"Sign out success": emptyProps(),
"Sign out failure": props<{ errors: BackendErrorsInterface }>(),
},
});
36 changes: 9 additions & 27 deletions nuxeo-admin-console-web/angular-app/src/app/auth/store/effects.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { HttpErrorResponse } from "@angular/common/http";
import { inject } from "@angular/core";
import { Router } from "@angular/router";

Check warning on line 3 in nuxeo-admin-console-web/angular-app/src/app/auth/store/effects.ts

View workflow job for this annotation

GitHub Actions / lint

'Router' is defined but never used
import { Actions, createEffect, ofType } from "@ngrx/effects";
import { catchError, map, of, switchMap, tap } from "rxjs";

Check warning on line 5 in nuxeo-admin-console-web/angular-app/src/app/auth/store/effects.ts

View workflow job for this annotation

GitHub Actions / lint

'tap' is defined but never used
import { PersistenceService } from "../../shared/services/persistence.service";
import { UserInterface } from "../../shared/types/user.interface";
import { AuthService } from "../services/auth.service";
Expand All @@ -12,16 +12,11 @@
(
actions$ = inject(Actions),
authService = inject(AuthService),
persistenceService = inject(PersistenceService)

Check warning on line 15 in nuxeo-admin-console-web/angular-app/src/app/auth/store/effects.ts

View workflow job for this annotation

GitHub Actions / lint

'persistenceService' is assigned a value but never used
) => {
return actions$.pipe(
ofType(authActions.getCurrentUser),
switchMap(() => {
const token = persistenceService.get("accessToken");

if (!token) {
return of(authActions.getCurrentUserFailure());
}
return authService.getCurrentUser().pipe(
map((currentUser: UserInterface) => {
return authActions.getCurrentUserSuccess({ currentUser });
Expand All @@ -36,23 +31,22 @@
{ functional: true }
);

export const ssoEffect = createEffect(
export const signOutEffect = createEffect(
(
actions$ = inject(Actions),
authService = inject(AuthService),
persistenceService = inject(PersistenceService)
) => {

return actions$.pipe(
ofType(authActions.sso),
switchMap(({ request }) => {
return authService.sso(request).pipe(
map((currentUser: UserInterface) => {
persistenceService.set("accessToken", currentUser.token);
return authActions.ssoSuccess({ currentUser });
ofType(authActions.signOut),
switchMap(() => {
return authService.signOut().pipe(
map(() => {
return authActions.signOutSuccess();
}),
catchError((errorResponse: HttpErrorResponse) => {
return of(
authActions.ssoFailure({
authActions.signOutFailure({
errors: errorResponse.error.errors,
})
);
Expand All @@ -61,17 +55,5 @@
})
);
},
{ functional: true }
);

export const redirectAfterSSOEffect = createEffect(
(actions$ = inject(Actions), router = inject(Router)) => {
return actions$.pipe(
ofType(authActions.ssoSuccess),
tap(() => {
router.navigateByUrl("/");
})
);
},
{ functional: true, dispatch: false }
);
);
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ const authFeature = createFeature({
on(authActions.getCurrentUser, (state) => ({
...state,
isLoading: true,
})),
}
)),
on(authActions.getCurrentUserSuccess, (state, action) => ({
...state,
isLoading: false,
Expand All @@ -46,6 +47,14 @@ const authFeature = createFeature({
on(routerNavigationAction, (state) => ({
...state,
validationErrors: null,
})),
on(authActions.signOutSuccess, (state) => ({
...state,
currentUser: null,
})),
on(authActions.signOutFailure, (state, { errors }) => ({
...state,
errors,
}))
),
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,13 @@ import { UserInterface } from "../../shared/types/user.interface";
export interface AuthResponseInterface {
user: UserInterface;
}

export interface AuthUserResponseInterface{
id:string,
properties:{
firstName:string,
lastName:string,
email: string;
username: string;
}
}
Loading
Loading