Skip to content

Commit 261de46

Browse files
committed
Add | Authorization service and API integration
1 parent d53982c commit 261de46

File tree

5 files changed

+205
-24
lines changed

5 files changed

+205
-24
lines changed

package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,15 @@
1010
"@testing-library/jest-dom": "^5.11.9",
1111
"@testing-library/react": "^11.2.5",
1212
"@testing-library/user-event": "^12.8.3",
13-
"axios": "^0.21.1",
13+
"axios": "^0.26.1",
1414
"clsx": "^1.1.1",
1515
"human-time": "0.0.2",
1616
"marked": "^2.0.1",
1717
"react": "^17.0.1",
1818
"react-dom": "^17.0.1",
1919
"react-router-dom": "^5.2.0",
2020
"react-scripts": "4.0.3",
21-
"rxjs": "^6.6.6",
21+
"rxjs": "^7.5.5",
2222
"web-vitals": "^1.1.1"
2323
},
2424
"scripts": {

src/App.js

+33-1
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,44 @@ import { catchError } from "rxjs/operators";
55
import { of } from "rxjs";
66
import './common/FlexBox.css';
77
import { BrowserRouter, Switch, Route } from "react-router-dom";
8-
import { HOME, PLANS } from "./components/routes";
98
import Layout from "./components/Layout";
109
import LinearProgress from "@material-ui/core/LinearProgress";
10+
import AuthorizationService from "./services/AuthorizationService";
1111

1212
function App() {
1313

14+
const [authorizing, setAuthorizing] = useState(true);
15+
const [error, setError] = useState(false);
16+
17+
useEffect(() => {
18+
if (authorizing) {
19+
20+
const params = QueryString.parse(window.location.search.slice(1, window.location.search.length));
21+
22+
AuthorizationService.token = params.token;
23+
24+
const subscription = AuthorizationService.getAccess().pipe(
25+
catchError(() => {
26+
setError(true);
27+
return of(null);
28+
})
29+
).subscribe(
30+
access => access && setAuthorizing(false)
31+
);
32+
33+
return () => subscription.unsubscribe();
34+
}
35+
}, [authorizing]);
36+
37+
38+
if (error) {
39+
return <ErrorBoundary/>
40+
}
41+
42+
if (authorizing) {
43+
return <LinearProgress className="full-width"/>;
44+
}
45+
1446
return (
1547
<BrowserRouter>
1648
<ErrorBoundary>

src/components/Layout.js

+32-8
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,7 @@
1-
import IconButton from "@material-ui/core/IconButton";
2-
import BackIcon from "@material-ui/icons/KeyboardBackspace";
3-
import React, { useEffect } from "react";
4-
import { useHistory, useLocation } from "react-router-dom";
1+
import React, { useEffect, useState } from "react";
52
import { makeStyles } from "@material-ui/core";
6-
import { HOME } from "./routes";
73
// import Plans from "./Plans";
8-
import { Switch, Route } from "react-router-dom";
4+
import AuthorizationService from "../services/AuthorizationService";
95

106
const H = 6;
117

@@ -31,11 +27,39 @@ export default function Layout() {
3127

3228
const classes = useStyles();
3329

30+
const [data, setData] = useState({});
31+
const [algorithms, setAlgorithms] = useState({});
32+
33+
useEffect(() => {
34+
const subscription = AuthorizationService.get(
35+
`setup/account/${AuthorizationService.getXTenantId()}`
36+
).subscribe(
37+
data => setData(data)
38+
);
39+
40+
return () => subscription.unsubscribe();
41+
}, []);
42+
43+
useEffect(() => {
44+
const subscription = AuthorizationService.get('setup/algorithm').subscribe(
45+
data => setAlgorithms(data)
46+
);
47+
48+
return () => subscription.unsubscribe();
49+
}, []);
50+
3451
return (
3552
<div className={classes.root}>
3653
<div className={classes.container}>
37-
<div className="flex justify-content-center align-items-center relative">
38-
<p>Hello Word</p>
54+
<div className="flex column">
55+
<strong>Tenant</strong>
56+
<pre>
57+
{JSON.stringify(data, null, 2)}
58+
</pre>
59+
<strong>Algorithms</strong>
60+
<pre>
61+
{JSON.stringify(algorithms, null, 2)}
62+
</pre>
3963
</div>
4064
</div>
4165
</div>

src/services/AuthorizationService.js

+125
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
import axios from "axios";
2+
import { from, fromEvent, of } from "rxjs";
3+
import { switchMap, filter, map, tap } from "rxjs/operators";
4+
5+
6+
const EnvironmentConfig = {
7+
cenitHost: 'http://127.0.0.1:3001', // TODO Configure via environment
8+
timeoutSpan: 3000,
9+
};
10+
11+
export const Config = EnvironmentConfig;
12+
13+
const apiGateway = axios.create({
14+
baseURL: `${Config.cenitHost}/api/v3`,
15+
timeout: Config.timeoutSpan,
16+
});
17+
18+
apiGateway.interceptors.request.use(async config => {
19+
const accessToken = await AuthorizationService.getAccessToken().toPromise();
20+
if (!config.headers) {
21+
config.headers = {};
22+
}
23+
config.headers.Authorization = `Bearer ${accessToken}`;
24+
const xTenantId = AuthorizationService.getXTenantId();
25+
if (xTenantId) {
26+
config.headers['X-Tenant-Id'] = xTenantId;
27+
}
28+
29+
return config;
30+
});
31+
32+
export const AccessKey = 'access';
33+
34+
const AuthorizationService = {
35+
36+
getXTenantId: function () {
37+
return this.xTenantId;
38+
},
39+
40+
setXTenantId: function (id) {
41+
this.xTenantId = id;
42+
},
43+
44+
getTenantAccess: function () {
45+
let access;
46+
try {
47+
access = this[AccessKey];
48+
let expirationDate = new Date(access.created_at + access.expires_in + Config.timeoutSpan);
49+
if (expirationDate < new Date()) {
50+
access = null;
51+
}
52+
} catch (e) {
53+
access = null;
54+
}
55+
56+
if (access) {
57+
return of({ access, tenantId: this.getXTenantId() });
58+
}
59+
60+
window.parent.postMessage({
61+
cmd: 'getAccess',
62+
token: this.token
63+
}, '*');
64+
65+
return fromEvent(window, 'message').pipe(
66+
map(({ data }) => data || {}),
67+
filter(({ access }) => access),
68+
tap(({ access, tenantId }) => {
69+
this[AccessKey] = access;
70+
this.setXTenantId(tenantId);
71+
}),
72+
)
73+
},
74+
75+
getAccess: function () {
76+
return this.getTenantAccess().pipe(
77+
map(({ access }) => access)
78+
);
79+
},
80+
81+
getAccessToken: function () {
82+
return this.getAccess().pipe(
83+
map(access => (access && access.access_token) || null)
84+
);
85+
},
86+
87+
get: function (path) {
88+
return from(apiGateway.get(path)).pipe(
89+
map(response => response.data)
90+
);
91+
},
92+
93+
post: function (path, data = null) {
94+
return from(apiGateway.post(path, data)).pipe(
95+
map(response => response.data)
96+
);
97+
},
98+
99+
delete: function (path, data = null) {
100+
return from(apiGateway.delete(path, { data })).pipe(
101+
map(response => response.data)
102+
);
103+
},
104+
105+
request: function (opts) {
106+
if (opts.path) {
107+
opts = { ...opts, url: `${Config.cenitHost}${opts.path}` }
108+
}
109+
return this.getAccess().pipe(
110+
switchMap(
111+
access => {
112+
const headers = { ...opts.headers };
113+
headers.Authorization = `Bearer ${access.access_token}`;
114+
opts = { ...opts, headers };
115+
return from(axios(opts));
116+
}
117+
),
118+
map(
119+
response => response.data
120+
)
121+
);
122+
}
123+
};
124+
125+
export default AuthorizationService;

yarn.lock

+13-13
Original file line numberDiff line numberDiff line change
@@ -2625,12 +2625,12 @@ axe-core@^4.3.5:
26252625
resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.4.1.tgz#7dbdc25989298f9ad006645cd396782443757413"
26262626
integrity sha512-gd1kmb21kwNuWr6BQz8fv6GNECPBnUasepcoLbekws23NVBLODdsClRZ+bQ8+9Uomf3Sm3+Vwn0oYG9NvwnJCw==
26272627

2628-
axios@^0.21.1:
2629-
version "0.21.4"
2630-
resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.4.tgz#c67b90dc0568e5c1cf2b0b858c43ba28e2eda575"
2631-
integrity sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==
2628+
axios@^0.26.1:
2629+
version "0.26.1"
2630+
resolved "https://registry.yarnpkg.com/axios/-/axios-0.26.1.tgz#1ede41c51fcf51bbbd6fd43669caaa4f0495aaa9"
2631+
integrity sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==
26322632
dependencies:
2633-
follow-redirects "^1.14.0"
2633+
follow-redirects "^1.14.8"
26342634

26352635
axobject-query@^2.2.0:
26362636
version "2.2.0"
@@ -5162,7 +5162,7 @@ flush-write-stream@^1.0.0:
51625162
inherits "^2.0.3"
51635163
readable-stream "^2.3.6"
51645164

5165-
follow-redirects@^1.0.0, follow-redirects@^1.14.0:
5165+
follow-redirects@^1.0.0, follow-redirects@^1.14.8:
51665166
version "1.14.9"
51675167
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.9.tgz#dd4ea157de7bfaf9ea9b3fbd85aa16951f78d8d7"
51685168
integrity sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w==
@@ -9829,12 +9829,12 @@ run-queue@^1.0.0, run-queue@^1.0.3:
98299829
dependencies:
98309830
aproba "^1.1.1"
98319831

9832-
rxjs@^6.6.6:
9833-
version "6.6.7"
9834-
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9"
9835-
integrity sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==
9832+
rxjs@^7.5.5:
9833+
version "7.5.5"
9834+
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.5.5.tgz#2ebad89af0f560f460ad5cc4213219e1f7dd4e9f"
9835+
integrity sha512-sy+H0pQofO95VDmFLzyaw9xNJU4KTRSwQIGM6+iG3SypAtCiLDzpeG8sJrNCWn2Up9km+KhkvTdbkrdy+yzZdw==
98369836
dependencies:
9837-
tslib "^1.9.0"
9837+
tslib "^2.1.0"
98389838

98399839
safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
98409840
version "5.1.2"
@@ -10884,12 +10884,12 @@ tsconfig-paths@^3.12.0:
1088410884
minimist "^1.2.6"
1088510885
strip-bom "^3.0.0"
1088610886

10887-
tslib@^1.8.1, tslib@^1.9.0:
10887+
tslib@^1.8.1:
1088810888
version "1.14.1"
1088910889
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
1089010890
integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
1089110891

10892-
tslib@^2.0.3:
10892+
tslib@^2.0.3, tslib@^2.1.0:
1089310893
version "2.3.1"
1089410894
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01"
1089510895
integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==

0 commit comments

Comments
 (0)