Merge pull request #354 from majd-asab/feature/add-github-auth
added login page with github authentication option
This commit is contained in:
@@ -18,6 +18,7 @@ import React, { FC, useContext } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Link, makeStyles, Typography } from '@material-ui/core';
|
||||
import HomeIcon from '@material-ui/icons/Home';
|
||||
import AccountCircle from '@material-ui/icons/AccountCircle';
|
||||
import {
|
||||
Sidebar,
|
||||
SidebarPage,
|
||||
@@ -77,6 +78,7 @@ const Root: FC<{}> = ({ children }) => (
|
||||
<SidebarSpacer />
|
||||
<SidebarDivider />
|
||||
<SidebarItem icon={HomeIcon} to="/" text="Home" />
|
||||
<SidebarItem icon={AccountCircle} to="/login" text="Login" />
|
||||
<SidebarDivider />
|
||||
<SidebarSpace />
|
||||
</Sidebar>
|
||||
|
||||
@@ -25,6 +25,7 @@ import {
|
||||
SystemIconKey,
|
||||
defaultSystemIcons,
|
||||
} from '../../icons';
|
||||
import LoginPage from './LoginPage';
|
||||
|
||||
class AppImpl implements App {
|
||||
constructor(private readonly systemIcons: SystemIcons) {}
|
||||
@@ -86,6 +87,10 @@ export default class AppBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
routes.push(
|
||||
<Route key="login" path="/login" component={LoginPage} exact />,
|
||||
);
|
||||
|
||||
return () => (
|
||||
<AppContextProvider app={app}>
|
||||
<Switch>
|
||||
|
||||
@@ -0,0 +1,177 @@
|
||||
/*
|
||||
* Copyright 2020 Spotify AB
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import React, { FC, useState } from 'react';
|
||||
import { GitHub as GitHubIcon } from '@material-ui/icons';
|
||||
import Page from '../../../layout/Page';
|
||||
import Header from '../../../layout/Header';
|
||||
import Content from '../../../layout/Content/Content';
|
||||
import ContentHeader from '../../../layout/ContentHeader/ContentHeader';
|
||||
import {
|
||||
Grid,
|
||||
Typography,
|
||||
Button,
|
||||
TextField,
|
||||
List,
|
||||
ListItem,
|
||||
Link
|
||||
} from '@material-ui/core';
|
||||
import InfoCard from '../../../layout/InfoCard/InfoCard';
|
||||
|
||||
enum AuthType {
|
||||
GitHub,
|
||||
}
|
||||
|
||||
const LoginPage: FC<{}> = () => {
|
||||
const [githubUsername, setGithubUsername] = useState(String);
|
||||
const [githubPersonalAuthToken, setGithubPersonalAuthToken] = useState(String);
|
||||
const [loginDetails, setLoginDetails] = useState(Object);
|
||||
|
||||
const saveGithubInfo = (info: {}) => {
|
||||
localStorage.setItem('githubLoginDetails', JSON.stringify(info));
|
||||
setLoginDetails(info);
|
||||
};
|
||||
|
||||
const deleteGithubInfo = () => {
|
||||
localStorage.removeItem('githubLoginDetails');
|
||||
setLoginDetails(undefined);
|
||||
};
|
||||
|
||||
const handleTokenRegistration = (event: any) => {
|
||||
switch (event.target.name) {
|
||||
case 'github-username-tf':
|
||||
setGithubUsername(event.target.value);
|
||||
break;
|
||||
case 'github-auth-tf':
|
||||
setGithubPersonalAuthToken(event.target.value);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
const fetchGitHubToken = (username: String, token: String) => {
|
||||
fetch('https://api.github.com/user', {
|
||||
headers: new Headers({
|
||||
Authorization: `Basic ${btoa(`${username}:${token}`)}`,
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
}),
|
||||
})
|
||||
.then((response) => {
|
||||
if (response.status === 200) return response.json();
|
||||
throw Error(`${response.status} ${response.statusText}`);
|
||||
})
|
||||
.then((data) => {
|
||||
const info = {
|
||||
username: username,
|
||||
token: token,
|
||||
name: data.name || data.login,
|
||||
};
|
||||
saveGithubInfo(info);
|
||||
})
|
||||
.catch(() => {});
|
||||
};
|
||||
|
||||
const validateUsernameAndToken = (username: String, token: String) => {
|
||||
if (username === undefined || username === null || username === '')
|
||||
return false;
|
||||
|
||||
if (token === undefined || token === null || token === '') return false;
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
const authenticate = (type: AuthType) => {
|
||||
switch (type) {
|
||||
case AuthType.GitHub:
|
||||
{
|
||||
const username = githubUsername;
|
||||
const token = githubPersonalAuthToken;
|
||||
if (validateUsernameAndToken(username, token))
|
||||
fetchGitHubToken(username, token);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
const LoginIndicator = () => {
|
||||
const ls = localStorage.getItem('githubLoginDetails');
|
||||
if (ls !== null) {
|
||||
const obj = ls || loginDetails ? JSON.parse(ls) : loginDetails;
|
||||
return (
|
||||
<Typography variant="h6" component="h2">
|
||||
{`Welcome, ${obj.name}!`}
|
||||
<br />
|
||||
<Link onClick={deleteGithubInfo}>Logout</Link>
|
||||
</Typography>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<Typography variant="h6" component="h2">
|
||||
Welcome, guest!
|
||||
</Typography>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<Page>
|
||||
<Header title="Login">
|
||||
<LoginIndicator />
|
||||
</Header>
|
||||
<Content>
|
||||
<ContentHeader title="Choose a method to authenticate" />
|
||||
<Grid container>
|
||||
<Grid item>
|
||||
<InfoCard>
|
||||
<Typography variant="h6">
|
||||
<GitHubIcon /> GitHub
|
||||
</Typography>
|
||||
<List>
|
||||
<ListItem>
|
||||
<TextField
|
||||
name="github-username-tf"
|
||||
label="Username"
|
||||
onChange={handleTokenRegistration}
|
||||
/>
|
||||
</ListItem>
|
||||
<ListItem>
|
||||
<TextField
|
||||
name="github-auth-tf"
|
||||
label="Token"
|
||||
onChange={handleTokenRegistration}
|
||||
/>
|
||||
</ListItem>
|
||||
<ListItem>
|
||||
<Button
|
||||
variant="outlined"
|
||||
color="primary"
|
||||
onClick={() => authenticate(AuthType.GitHub)}
|
||||
>
|
||||
Authenticate
|
||||
</Button>
|
||||
</ListItem>
|
||||
</List>
|
||||
</InfoCard>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Content>
|
||||
</Page>
|
||||
);
|
||||
};
|
||||
|
||||
export default LoginPage;
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright 2020 Spotify AB
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export { default } from './LoginPage';
|
||||
Reference in New Issue
Block a user