diff --git a/components/automate-ui/src/app/entities/servers/server.actions.ts b/components/automate-ui/src/app/entities/servers/server.actions.ts index 98ae1212bc5..29e41a178d2 100644 --- a/components/automate-ui/src/app/entities/servers/server.actions.ts +++ b/components/automate-ui/src/app/entities/servers/server.actions.ts @@ -2,6 +2,7 @@ import { HttpErrorResponse } from '@angular/common/http'; import { Action } from '@ngrx/store'; import { Server , User, WebUIKey } from './server.model'; +import { ValidateWebUIKeyResponse } from './server.requests'; export enum ServerActionTypes { GET_ALL = 'SERVER::GET_ALL', @@ -24,7 +25,11 @@ export enum ServerActionTypes { GET_USERS_FAILURE = 'SERVER::GET_USERS::FAILURE', UPDATE_WEB_UI_KEY = 'SERVER::UPDATE_WEB_UI_KEY', UPDATE_WEB_UI_KEY_SUCCESS = 'SERVER::UPDATE_WEB_UI_KEY::SUCCESS', - UPDATE_WEB_UI_KEY_FAILURE = 'SERVER::UPDATE_WEB_UI_KEY::FAILURE' + UPDATE_WEB_UI_KEY_FAILURE = 'SERVER::UPDATE_WEB_UI_KEY::FAILURE', + VALIDATE_WEB_UI_KEY = 'SERVER::VALIDATE_WEB_UI_KEY', + VALIDATE_WEB_UI_KEY_SUCCESS = 'SERVER::VALIDATE_WEB_UI_KEY::SUCCESS', + VALIDATE_WEB_UI_KEY_SUCCESS_NOT= 'SERVER::VALIDATE_WEB_UI_KEY::SUCCESS_NOT', + VALIDATE_WEB_UI_KEY_FAILURE = 'SERVER::VALIDATE_WEB_UI_KEY::FAILURE' } @@ -170,6 +175,30 @@ export class UpdateWebUIKeyFailure implements Action { constructor(public payload: HttpErrorResponse) { } } +export class ValidateWebUIKey implements Action { + readonly type = ServerActionTypes.VALIDATE_WEB_UI_KEY; + + constructor(public payload: Server) { } +} + +export class ValidateWebUIKeySuccess implements Action { + readonly type = ServerActionTypes.VALIDATE_WEB_UI_KEY_SUCCESS; + + constructor(public payload: ValidateWebUIKeyResponse) { } +} + +export class ValidateWebUIKeySuccessNot implements Action { + readonly type = ServerActionTypes.VALIDATE_WEB_UI_KEY_SUCCESS_NOT; + + constructor(public payload: ValidateWebUIKeyResponse) { } +} + +export class ValidateWebUIKeyFailure implements Action { + readonly type = ServerActionTypes.VALIDATE_WEB_UI_KEY_FAILURE; + + constructor(public payload: HttpErrorResponse) { } +} + export type ServerActions = | GetServers | GetServersSuccess @@ -191,4 +220,8 @@ export type ServerActions = | GetUsersFailure | UpdateWebUIKey | UpdateWebUIKeySuccess - | UpdateWebUIKeyFailure; + | UpdateWebUIKeyFailure + | ValidateWebUIKey + | ValidateWebUIKeySuccess + | ValidateWebUIKeySuccessNot + | ValidateWebUIKeyFailure; diff --git a/components/automate-ui/src/app/entities/servers/server.effects.ts b/components/automate-ui/src/app/entities/servers/server.effects.ts index 9661c91fb2d..920fbfa0719 100644 --- a/components/automate-ui/src/app/entities/servers/server.effects.ts +++ b/components/automate-ui/src/app/entities/servers/server.effects.ts @@ -32,12 +32,17 @@ import { UsersSuccessPayload, UpdateWebUIKey, UpdateWebUIKeySuccess, - UpdateWebUIKeyFailure + UpdateWebUIKeyFailure, + ValidateWebUIKey, + ValidateWebUIKeySuccess, + ValidateWebUIKeyFailure, + ValidateWebUIKeySuccessNot } from './server.actions'; import { ServerRequests, - ServerResponse + ServerResponse, + ValidateWebUIKeyResponse } from './server.requests'; @Injectable() @@ -216,4 +221,34 @@ export class ServerEffects { message: `Could not update Web UI Key ${msg || payload.error}.` }); }))); + + ValidateWebUIKey$ = createEffect(() => this.actions$.pipe( + ofType(ServerActionTypes.VALIDATE_WEB_UI_KEY), + mergeMap(({ payload }: ValidateWebUIKey) => + this.requests.validateWebUIKey(payload).pipe( + map((resp: ValidateWebUIKeyResponse) => + resp.valid ? new ValidateWebUIKeySuccess(resp) : new ValidateWebUIKeySuccessNot(resp)), + catchError((error: HttpErrorResponse) => observableOf(new ValidateWebUIKeyFailure(error)) + ))))); + + ValidateWebUIKeySuccessNot$ = createEffect(() => this.actions$.pipe( + ofType(ServerActionTypes.VALIDATE_WEB_UI_KEY_SUCCESS_NOT), + map(({ payload }: ValidateWebUIKeySuccessNot) => { + if (!payload.valid) { + return new CreateNotification({ + type: Type.error, + message: `Invalid webui key: ${payload.error}` + }); + } + }))); + + ValidateWebUIKeyFailure$ = createEffect(() => this.actions$.pipe( + ofType(ServerActionTypes.VALIDATE_WEB_UI_KEY_FAILURE), + map(({ payload }: UpdateWebUIKeyFailure) => { + const msg = payload.error.error; + return new CreateNotification({ + type: Type.error, + message: `Could not validated Web UI Key ${msg || payload.error}.` + }); + }))); } diff --git a/components/automate-ui/src/app/entities/servers/server.reducer.ts b/components/automate-ui/src/app/entities/servers/server.reducer.ts index b73cf256520..2ddc07f713c 100644 --- a/components/automate-ui/src/app/entities/servers/server.reducer.ts +++ b/components/automate-ui/src/app/entities/servers/server.reducer.ts @@ -4,6 +4,7 @@ import { pipe, set, unset } from 'lodash/fp'; import { EntityStatus } from 'app/entities/entities'; import { ServerActionTypes, ServerActions } from './server.actions'; import { Server, User } from './server.model'; +import { ValidateWebUIKeyResponse } from './server.requests'; export interface ServerEntityState extends EntityState { getAllStatus: EntityStatus; @@ -15,16 +16,19 @@ export interface ServerEntityState extends EntityState { getUsers: User[]; getUsersStatus: EntityStatus; updateWebUIKeyStatus: EntityStatus; + getvalidateWebUIKeyStatus: ValidateWebUIKeyResponse; + validateWebUIKeyStatus: EntityStatus; } -const GET_ALL_STATUS = 'getAllStatus'; -const SAVE_STATUS = 'saveStatus'; -const SAVE_ERROR = 'saveError'; -const UPDATE_STATUS = 'updateStatus'; -const GET_STATUS = 'getStatus'; -const DELETE_STATUS = 'deleteStatus'; -const GET_USERS_STATUS = 'getUsersStatus'; -const UPDATE_WEB_UI_KEY_STATUS = 'updateWebUIKeyStatus'; +const GET_ALL_STATUS = 'getAllStatus'; +const SAVE_STATUS = 'saveStatus'; +const SAVE_ERROR = 'saveError'; +const UPDATE_STATUS = 'updateStatus'; +const GET_STATUS = 'getStatus'; +const DELETE_STATUS = 'deleteStatus'; +const GET_USERS_STATUS = 'getUsersStatus'; +const UPDATE_WEB_UI_KEY_STATUS = 'updateWebUIKeyStatus'; +const VALIDATE_WEB_UI_KEY_STATUS = 'validateWebUIKeyStatus'; export const serverEntityAdapter: EntityAdapter = createEntityAdapter(); @@ -38,7 +42,9 @@ export const ServerEntityInitialState: ServerEntityState = deleteStatus: EntityStatus.notLoaded, getUsers: null, getUsersStatus: EntityStatus.notLoaded, - updateWebUIKeyStatus: EntityStatus.notLoaded + updateWebUIKeyStatus: EntityStatus.notLoaded, + getvalidateWebUIKeyStatus: null, + validateWebUIKeyStatus: EntityStatus.notLoaded }); export function serverEntityReducer( @@ -148,11 +154,22 @@ export function serverEntityReducer( return set(UPDATE_WEB_UI_KEY_STATUS, EntityStatus.loading, state); case ServerActionTypes.UPDATE_WEB_UI_KEY_SUCCESS: - return set(UPDATE_WEB_UI_KEY_STATUS, EntityStatus.loadingSuccess, - state); + return set(UPDATE_WEB_UI_KEY_STATUS, EntityStatus.loadingSuccess, state); case ServerActionTypes.UPDATE_WEB_UI_KEY_FAILURE: return set(UPDATE_WEB_UI_KEY_STATUS, EntityStatus.loadingFailure, state); + + case ServerActionTypes.VALIDATE_WEB_UI_KEY: + return set(VALIDATE_WEB_UI_KEY_STATUS, EntityStatus.loading, state); + + case ServerActionTypes.VALIDATE_WEB_UI_KEY_SUCCESS: + return pipe( + set(VALIDATE_WEB_UI_KEY_STATUS, EntityStatus.loadingSuccess), + set('getvalidateWebUIKeyStatus', action.payload || {}) + )(state) as ServerEntityState; + + case ServerActionTypes.VALIDATE_WEB_UI_KEY_FAILURE: + return set(VALIDATE_WEB_UI_KEY_STATUS, EntityStatus.loadingFailure, state); } return state; diff --git a/components/automate-ui/src/app/entities/servers/server.requests.ts b/components/automate-ui/src/app/entities/servers/server.requests.ts index 421fe294982..8acaf30c442 100644 --- a/components/automate-ui/src/app/entities/servers/server.requests.ts +++ b/components/automate-ui/src/app/entities/servers/server.requests.ts @@ -19,6 +19,11 @@ export interface UserResponse { users: User[]; } +export interface ValidateWebUIKeyResponse { + valid: boolean; + error: string; +} + @Injectable() export class ServerRequests { @@ -50,9 +55,13 @@ export class ServerRequests { return this.http.get(`${env.infra_proxy_url}/servers/${payload.server_id}/automateinfraserverusers`); } - // Need to change API endpoint for update WebUIKey - public updateWebUIKey(payload): Observable { + public updateWebUIKey(payload: WebUIKey): Observable { return this.http.post (`${env.infra_proxy_url}/servers/update`, payload); } + + public validateWebUIKey(payload: Server): Observable { + return this.http.post + (`${env.infra_proxy_url}/servers/validate`, payload); + } } diff --git a/components/automate-ui/src/app/entities/servers/server.selectors.ts b/components/automate-ui/src/app/entities/servers/server.selectors.ts index 8b3aa44ad26..88b20b1b232 100644 --- a/components/automate-ui/src/app/entities/servers/server.selectors.ts +++ b/components/automate-ui/src/app/entities/servers/server.selectors.ts @@ -61,3 +61,13 @@ export const updateWebUIKey = createSelector( serverState, (state) => state.updateWebUIKeyStatus ); + +export const getValidateWebUIKeyStatus = createSelector( + serverState, + (state) => state.getvalidateWebUIKeyStatus +); + +export const validateWebUIKeyStatus = createSelector( + serverState, + (state) => state.validateWebUIKeyStatus +); diff --git a/components/automate-ui/src/app/modules/infra-proxy/chef-server-details/chef-server-details.component.html b/components/automate-ui/src/app/modules/infra-proxy/chef-server-details/chef-server-details.component.html index ec52424c5c2..c0f75b3dc0c 100644 --- a/components/automate-ui/src/app/modules/infra-proxy/chef-server-details/chef-server-details.component.html +++ b/components/automate-ui/src/app/modules/infra-proxy/chef-server-details/chef-server-details.component.html @@ -23,9 +23,10 @@
  • Web UI Key - Valid - warning - Invalid + Validating... + Valid + warning + Invalid { }); }); }); + + describe('validate server webui key on details page', () => { + it('when server webui key is valid', () => { + expect(element.query(By.css('.webUIKeyStatus'))).toBeDefined(); + }); + }); }); diff --git a/components/automate-ui/src/app/modules/infra-proxy/chef-server-details/chef-server-details.component.ts b/components/automate-ui/src/app/modules/infra-proxy/chef-server-details/chef-server-details.component.ts index 012a0f32e95..c4e325c3517 100644 --- a/components/automate-ui/src/app/modules/infra-proxy/chef-server-details/chef-server-details.component.ts +++ b/components/automate-ui/src/app/modules/infra-proxy/chef-server-details/chef-server-details.component.ts @@ -13,11 +13,22 @@ import { Regex } from 'app/helpers/auth/regex'; import { LayoutFacadeService, Sidebar } from 'app/entities/layout/layout.facade'; import { pending, EntityStatus, allLoaded } from 'app/entities/entities'; import { - getStatus, serverFromRoute, updateStatus, getUsers, getUsersStatus, updateWebUIKey + getStatus, + serverFromRoute, + updateStatus, + getUsers, + getUsersStatus, + updateWebUIKey, + validateWebUIKeyStatus, + getValidateWebUIKeyStatus } from 'app/entities/servers/server.selectors'; import { Server, WebUIKey } from 'app/entities/servers/server.model'; -import { GetServer, UpdateServer, UpdateWebUIKey +import { + GetServer, + UpdateServer, + UpdateWebUIKey, + ValidateWebUIKey // , GetUsers } from 'app/entities/servers/server.actions'; import { GetOrgs, CreateOrg, DeleteOrg } from 'app/entities/orgs/org.actions'; @@ -67,6 +78,8 @@ export class ChefServerDetailsComponent implements OnInit, OnDestroy { public usersListLoading; public authFailure = false; public isValid = false; + public isServerLoaded = false; + public validating = true; public updateWebuiKeyForm: FormGroup; @@ -175,6 +188,7 @@ export class ChefServerDetailsComponent implements OnInit, OnDestroy { this.creatingServerOrg = false; this.orgsListLoading = false; this.closeCreateModal(); + this.isServerLoaded = true; }); combineLatest([ @@ -241,6 +255,12 @@ export class ChefServerDetailsComponent implements OnInit, OnDestroy { this.isValid = true; } }); + + setTimeout(() => { + if (this.isServerLoaded) { + this.validateWebUIKey(this.server); + } + }, 1000); } ngOnDestroy(): void { @@ -302,6 +322,22 @@ export class ChefServerDetailsComponent implements OnInit, OnDestroy { this.deleteModalVisible = false; } + // validate the webui ui key + private validateWebUIKey(server: Server): void { + this.store.dispatch(new ValidateWebUIKey(server)); + combineLatest([ + this.store.select(validateWebUIKeyStatus), + this.store.select(getValidateWebUIKeyStatus) + ]).pipe(takeUntil(this.isDestroyed)) + .subscribe(([validateWebUISt, getValidateWebUIkeyState]) => { + if (validateWebUISt === EntityStatus.loadingSuccess && !isNil(getValidateWebUIkeyState)) { + this.isValid = getValidateWebUIkeyState.valid; + this.isServerLoaded = false; + } + this.validating = false; + }); + } + saveServer(): void { this.saveSuccessful = false; this.saveInProgress = true; @@ -314,7 +350,6 @@ export class ChefServerDetailsComponent implements OnInit, OnDestroy { this.store.dispatch(new UpdateServer({server: updatedServer})); } - public updateWebuiKey(): void { this.updatingWebuiKey = true; this.webuiKey = { @@ -324,6 +359,7 @@ export class ChefServerDetailsComponent implements OnInit, OnDestroy { this.updatingWebuiKeyData(this.webuiKey); this.updateWebuiKeyForm.reset(); } + private updatingWebuiKeyData(webuikey: WebUIKey) { this.store.dispatch(new UpdateWebUIKey(webuikey)); } diff --git a/e2e/cypress/integration/ui/infra-proxy/chef-server-details.spec.ts b/e2e/cypress/integration/ui/infra-proxy/chef-server-details.spec.ts index d536d31f902..5f9f7081ab6 100644 --- a/e2e/cypress/integration/ui/infra-proxy/chef-server-details.spec.ts +++ b/e2e/cypress/integration/ui/infra-proxy/chef-server-details.spec.ts @@ -8,6 +8,7 @@ describe('chef server details', () => { const customServerID = `${cypressPrefix}-custom-id-${now}`; const serverFQDN = 'chef-server-1617089723092818000.com'; const serverIP = '176.119.50.159'; + const webui_key = 'Dummy--webui--key'; const orgName = `${cypressPrefix} org ${now}`; const generatedOrgID = orgName.split(' ').join('-'); const customOrgID = `${cypressPrefix}-custom-id-${now}`; @@ -15,7 +16,6 @@ describe('chef server details', () => { // using dummy admin key value for creating the org const adminKey = 'Dummy--admin--key'; - const webui_key = 'Dummy--webui-key'; before(() => { cy.adminLogin('/').then(() => { @@ -67,6 +67,10 @@ describe('chef server details', () => { cy.get('app-chef-server-details .sidenav-header').should('not.be.visible'); }); + it('can validate the server webui key', () => { + cy.get('[data-cy=valid-webui-key]').contains('Valid'); + }); + it('can check empty org list', () => { cy.get('#org-table-container chef-th').should('not.be.visible'); cy.get('[data-cy=empty-list]').should('be.visible');