From ec335629b45bc26c1606d80749c5b929a09d6dcf Mon Sep 17 00:00:00 2001 From: Stan Silvert Date: Mon, 22 Oct 2018 16:09:23 -0400 Subject: [PATCH] KEYCLOAK: 8601: Evaluate REST/HTTP packages for React --- .../theme/keycloak-preview/account/index.ftl | 2 +- .../app/account-service/account.service.ts | 150 ++++++++---------- .../app/content/account-page/AccountPage.tsx | 30 +++- .../account/resources/package-lock.json | 35 ++++ .../account/resources/package.json | 1 + .../account/resources/systemjs.config.js | 1 + 6 files changed, 131 insertions(+), 88 deletions(-) diff --git a/themes/src/main/resources/theme/keycloak-preview/account/index.ftl b/themes/src/main/resources/theme/keycloak-preview/account/index.ftl index 4d0f093c7a..5c6a1951d3 100644 --- a/themes/src/main/resources/theme/keycloak-preview/account/index.ftl +++ b/themes/src/main/resources/theme/keycloak-preview/account/index.ftl @@ -122,7 +122,7 @@ if (loadListener) script.addEventListener("load", loadListener); document.head.appendChild(script); }; - keycloak.init({onLoad: 'check-sso'}).success(function(authenticated) { + keycloak.init({onLoad: 'login-required'}).success(function(authenticated) { loadjs("/node_modules/react/umd/react.development.js", function() { loadjs("/node_modules/react-dom/umd/react-dom.development.js", function() { loadjs("/node_modules/systemjs/dist/system.src.js", function() { diff --git a/themes/src/main/resources/theme/keycloak-preview/account/resources/app/account-service/account.service.ts b/themes/src/main/resources/theme/keycloak-preview/account/resources/app/account-service/account.service.ts index 71cb4afeab..1374d57dbb 100644 --- a/themes/src/main/resources/theme/keycloak-preview/account/resources/app/account-service/account.service.ts +++ b/themes/src/main/resources/theme/keycloak-preview/account/resources/app/account-service/account.service.ts @@ -1,5 +1,5 @@ /* - * Copyright 2017 Red Hat Inc. and/or its affiliates and other contributors + * Copyright 2018 Red Hat Inc. and/or its affiliates and other contributors * as indicated by the @author tags. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not @@ -15,98 +15,82 @@ * the License. */ -/*import {Injectable} from '@angular/core'; -import {Http, Response, RequestOptionsArgs} from '@angular/http'; - -import {KeycloakNotificationService} from '../notification/keycloak-notification.service'; +//import {KeycloakNotificationService} from '../notification/keycloak-notification.service'; import {KeycloakService} from '../keycloak-service/keycloak.service'; +import Axios, {AxiosRequestConfig, AxiosResponse, AxiosPromise} from 'axios'; -import {NotificationType} from 'patternfly-ng/notification';*/ +//import {NotificationType} from 'patternfly-ng/notification';*/ +type AxiosResolve = (AxiosResponse) => void; +type ConfigResolve = (AxiosRequestConfig) => void; +type ErrorReject = (Error) => void; + /** * - * @author Stan Silvert ssilvert@redhat.com (C) 2017 Red Hat Inc. + * @author Stan Silvert ssilvert@redhat.com (C) 2018 Red Hat Inc. */ -//@Injectable() export class AccountServiceClient { - - /* private accountUrl: string; - - constructor(protected http: Http, - protected kcSvc: KeycloakService, - protected kcNotifySvc: KeycloakNotificationService) { - this.accountUrl = kcSvc.authServerUrl() + 'realms/' + kcSvc.realm() + '/account'; + private static instance: AccountServiceClient = new AccountServiceClient(); + + private kcSvc: KeycloakService = KeycloakService.Instance; + private accountUrl: string = this.kcSvc.authServerUrl() + 'realms/' + this.kcSvc.realm() + '/account'; + + private constructor() {} + + public static get Instance(): AccountServiceClient { + return this.instance; } - public doGetRequest(endpoint: string, - responseHandler: Function, - options?: RequestOptionsArgs) { - this.http.get(this.accountUrl + endpoint, options) - .subscribe((res: Response) => responseHandler(res), - (error: Response) => this.handleServiceError(error)); + public doGet(endpoint: string, + config?: AxiosRequestConfig): Promise { + return this.doRequest(endpoint, {...config, method: 'get'}); } - public doPostRequest(endpoint: string, - responseHandler: Function, - options?: RequestOptionsArgs, - successMessage?: string) { - this.http.post(this.accountUrl + endpoint, options) - .subscribe((res: Response) => this.handleAccountUpdated(responseHandler, res, successMessage), - (error: Response) => this.handleServiceError(error)); - } - - private handleAccountUpdated(responseHandler: Function, res: Response, successMessage?: string) { - let message: string = "Your account has been updated."; - if (successMessage) message = successMessage; - this.kcNotifySvc.notify(message, NotificationType.SUCCESS); - responseHandler(res); - } - - public doDelete(endpoint: string, - responseHandler: Function, - options?: RequestOptionsArgs, - successMessage?: string) { - this.http.delete(this.accountUrl + endpoint, options) - .subscribe((res: Response) => this.handleAccountUpdated(responseHandler, res, successMessage), - (error: Response) => this.handleServiceError(error)); - } - - private handleServiceError(response: Response): void { - console.log('**** ERROR!!!! ***'); - console.log(JSON.stringify(response)); - console.log("response.status=" + response.status); - console.log('***************************************') + public doRequest(endpoint: string, + config?: AxiosRequestConfig): Promise { - if ((response.status === undefined) || (response.status === 401)) { - this.kcSvc.logout(); - return; - } - - if (response.status === 403) { - // TODO: go to a forbidden page? - } - - if (response.status === 404) { - // TODO: route to PageNotFoundComponent - } - - let message: string = response.status + " " + response.statusText; - - const not500Error: boolean = response.status !== 500; - console.log('not500Error=' + not500Error); - - // Unfortunately, errors can be sent back in the response body as - // 'errorMessage' or 'error_description' - if (not500Error && response.json().hasOwnProperty('errorMessage')) { - message = response.json().errorMessage; - } - - if (not500Error && response.json().hasOwnProperty('error_description')) { - message = response.json().error_description; - } - - this.kcNotifySvc.notify(message, NotificationType.DANGER, response.json().params); - } */ + return new Promise((resolve: AxiosResolve, reject: ErrorReject) => { + this.makeConfig(endpoint, config) + .then((config: AxiosRequestConfig) => { + console.log({config}); + this.axiosRequest(config, resolve, reject); + }).catch( (error: Error) => { + this.handleError(error); + reject(error); + }); + }); + } + + private axiosRequest(config: AxiosRequestConfig, + resolve: AxiosResolve, + reject: ErrorReject): void { + Axios.request(config) + .then((response: AxiosResponse) => { + resolve(response); + }) + .catch((error: Error) => { + this.handleError(error); + reject(error); + }); + } + + private handleError(error: Error) { + console.log(error); + } + + private makeConfig(endpoint: string, config?: AxiosRequestConfig): Promise { + return new Promise( (resolve: ConfigResolve, reject: ErrorReject) => { + this.kcSvc.getToken() + .then( (token: string) => { + resolve( { + ...config, + baseURL: this.accountUrl, + url: endpoint, + headers: {...config.headers, Authorization: 'Bearer ' + token} + }); + }).catch((error: Error) => { + reject(error); + }); + }); + } } - - diff --git a/themes/src/main/resources/theme/keycloak-preview/account/resources/app/content/account-page/AccountPage.tsx b/themes/src/main/resources/theme/keycloak-preview/account/resources/app/content/account-page/AccountPage.tsx index a17684a051..6bfee81985 100644 --- a/themes/src/main/resources/theme/keycloak-preview/account/resources/app/content/account-page/AccountPage.tsx +++ b/themes/src/main/resources/theme/keycloak-preview/account/resources/app/content/account-page/AccountPage.tsx @@ -15,20 +15,42 @@ */ import * as React from 'react'; +import {AxiosResponse} from 'axios'; +import {AccountServiceClient} from '../../account-service/account.service'; -export interface AccountPageProps { +interface AccountPageProps { } - -export class AccountPage extends React.Component { + +interface AccountPageState { + readonly username: string, + readonly firstName?: string, + readonly lastName?: string, + readonly email?: string, + readonly emailVerified?: boolean +} + +/** + * @author Stan Silvert ssilvert@redhat.com (C) 2018 Red Hat Inc. + */ +export class AccountPage extends React.Component { + readonly state: AccountPageState = { + username: '' + }; constructor(props: AccountPageProps) { super(props); + AccountServiceClient.Instance.doGet("/") + .then((response: AxiosResponse) => { + this.setState(response.data); + console.log({response}); + }); } render() { + const {username, firstName} = this.state; return (
-

Hello Account Page

+

Hello {username} {firstName}

); } diff --git a/themes/src/main/resources/theme/keycloak-preview/account/resources/package-lock.json b/themes/src/main/resources/theme/keycloak-preview/account/resources/package-lock.json index 9df53b12bc..d90b32488f 100644 --- a/themes/src/main/resources/theme/keycloak-preview/account/resources/package-lock.json +++ b/themes/src/main/resources/theme/keycloak-preview/account/resources/package-lock.json @@ -294,6 +294,15 @@ "@types/react": "*" } }, + "axios": { + "version": "0.18.0", + "resolved": "http://registry.npmjs.org/axios/-/axios-0.18.0.tgz", + "integrity": "sha1-MtU+SFHv3AoRmTts0AB4nXDAUQI=", + "requires": { + "follow-redirects": "^1.3.0", + "is-buffer": "^1.1.5" + } + }, "bootstrap": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.1.3.tgz", @@ -411,6 +420,14 @@ "jquery": ">=1.7" } }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + }, "drmonty-datatables-colvis": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/drmonty-datatables-colvis/-/drmonty-datatables-colvis-1.1.2.tgz", @@ -440,6 +457,14 @@ } } }, + "follow-redirects": { + "version": "1.5.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.9.tgz", + "integrity": "sha512-Bh65EZI/RU8nx0wbYF9shkFZlqLP+6WT/5FnA3cE/djNSuKNHJEinGGZgu/cQEkeeb2GdFOgenAmn8qaqYke2w==", + "requires": { + "debug": "=3.1.0" + } + }, "font-awesome": { "version": "4.7.0", "resolved": "https://registry.npmjs.org/font-awesome/-/font-awesome-4.7.0.tgz", @@ -492,6 +517,11 @@ "loose-envify": "^1.0.0" } }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + }, "isarray": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", @@ -535,6 +565,11 @@ "moment": ">= 2.6.0" } }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", diff --git a/themes/src/main/resources/theme/keycloak-preview/account/resources/package.json b/themes/src/main/resources/theme/keycloak-preview/account/resources/package.json index 0b9980d090..9d79decd23 100644 --- a/themes/src/main/resources/theme/keycloak-preview/account/resources/package.json +++ b/themes/src/main/resources/theme/keycloak-preview/account/resources/package.json @@ -10,6 +10,7 @@ "author": "Stan Silvert", "license": "Apache 2.0", "dependencies": { + "axios": "^0.18.0", "bootstrap": "^4.1.0", "patternfly": "^3.23.2", "react": "^16.5.2", diff --git a/themes/src/main/resources/theme/keycloak-preview/account/resources/systemjs.config.js b/themes/src/main/resources/theme/keycloak-preview/account/resources/systemjs.config.js index c80d77923f..7f1f5d6ae7 100644 --- a/themes/src/main/resources/theme/keycloak-preview/account/resources/systemjs.config.js +++ b/themes/src/main/resources/theme/keycloak-preview/account/resources/systemjs.config.js @@ -18,6 +18,7 @@ 'react-dom': 'npm:react-dom/umd/react-dom.development.js', 'react-router-dom': 'npm:react-router-dom/umd/react-router-dom.js', + 'axios': 'npm:axios/dist/axios.min.js', }, bundles: {