Integrate login and auth server API
This commit is contained in:
@@ -2,46 +2,71 @@ import React, { Component } from 'react';
|
||||
import Categories from './Categories';
|
||||
import Category from './Category';
|
||||
import Tool from './Tool';
|
||||
import { Container, Dimmer, Dropdown, Header, Icon, Item, Loader, Menu, Segment, Input } from 'semantic-ui-react';
|
||||
import { Button, Confirm, Container, Dimmer, Form, Header, Icon, Item, Label, Loader, Menu, Message, Segment, Input } from 'semantic-ui-react';
|
||||
import { Link, Route } from 'react-router-dom';
|
||||
import io from 'socket.io-client';
|
||||
|
||||
// Move to env var
|
||||
const SERVER_URL = 'http://localhost:8080';
|
||||
const SOCKET_SERVER_URL = 'http://localhost:8080';
|
||||
const AUTH_SERVER_URL = 'http://localhost:8000';
|
||||
|
||||
class App extends Component {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.socket = io(SERVER_URL);
|
||||
this.socket = io(SOCKET_SERVER_URL);
|
||||
this.storage = typeof localStorage !== 'undefined';
|
||||
|
||||
let token = this.storage ? localStorage.getItem('token') : null;
|
||||
|
||||
this.state = {
|
||||
login: {token: token, error: null, username: '', password: '', confirmLogout: false},
|
||||
user: null,
|
||||
toolData: null,
|
||||
toolStatus: null,
|
||||
connected: false,
|
||||
network: true,
|
||||
};
|
||||
}
|
||||
|
||||
getUser = () => {
|
||||
fetch(AUTH_SERVER_URL + '/user/', {
|
||||
headers: {'Authorization': 'Token ' + this.state.login.token},
|
||||
})
|
||||
.then(response => {
|
||||
if (response.ok) {
|
||||
response.json().then(data => this.setState({ user: data[0] }));
|
||||
} else {
|
||||
this.handleLogout();
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.log(error)
|
||||
});
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
fetch(SERVER_URL + '/api/tooldata')
|
||||
fetch(AUTH_SERVER_URL + '/tooldata/')
|
||||
.then(response => response.json())
|
||||
.then(data => this.setState({ toolData: data }));
|
||||
fetch(SERVER_URL + '/api/user')
|
||||
.then(response => response.json())
|
||||
.then(data => this.setState({ user: data }));
|
||||
.then(data => this.setState({ toolData: data }))
|
||||
.catch(error => {
|
||||
console.log(error)
|
||||
this.setState({network: false});
|
||||
});
|
||||
|
||||
if (this.state.login.token) this.getUser();
|
||||
|
||||
this.socket.on('toolStatus', toolStatus =>
|
||||
this.setState({ toolStatus: toolStatus })
|
||||
);
|
||||
|
||||
this.socket.on('connect', toolStatus =>
|
||||
this.socket.on('connect', () =>
|
||||
this.setState({ connected: true })
|
||||
);
|
||||
|
||||
this.socket.on('disconnect', toolStatus =>
|
||||
this.setState({ toolStatus: null, connected: false })
|
||||
);
|
||||
this.socket.on('disconnect', () => {
|
||||
this.setState({ toolStatus: null, connected: false });
|
||||
});
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
@@ -50,63 +75,161 @@ class App extends Component {
|
||||
|
||||
requestInterlock = change => {
|
||||
this.socket.emit('requestInterlock', {
|
||||
username: this.state.user.username,
|
||||
token: this.state.login.token,
|
||||
change: change,
|
||||
});
|
||||
}
|
||||
|
||||
handleChange = event => {
|
||||
const name = event.target.name;
|
||||
const value = event.target.value;
|
||||
|
||||
this.setState({
|
||||
login: {...this.state.login, [name]: value}
|
||||
});
|
||||
}
|
||||
|
||||
handleSubmit = () => {
|
||||
const login = this.state.login;
|
||||
fetch(AUTH_SERVER_URL + '/login/', {
|
||||
method: 'POST',
|
||||
headers: {'Content-Type': 'application/json; charset=utf-8'},
|
||||
body: JSON.stringify({'username': login.username, 'password': login.password})
|
||||
})
|
||||
.then(response => {
|
||||
if (response.ok) {
|
||||
response.json().then(data => {
|
||||
this.setState({login: {...login, ...data, error: false}});
|
||||
if (this.storage) localStorage.setItem('token', data.token);
|
||||
this.getUser();
|
||||
});
|
||||
} else {
|
||||
this.setState({login: {...login, error: true}});
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.log(error)
|
||||
this.setState({network: false});
|
||||
});
|
||||
}
|
||||
|
||||
confirmLogout = () => {
|
||||
if (this.state.login.token) {
|
||||
this.setState({
|
||||
login: {...this.state.login, confirmLogout: true}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
cancelLogout = () => {
|
||||
this.setState({
|
||||
login: {...this.state.login, confirmLogout: false}
|
||||
});
|
||||
}
|
||||
|
||||
handleLogout = () => {
|
||||
this.setState({
|
||||
login: {...this.state.login, token: null, confirmLogout: false}
|
||||
});
|
||||
localStorage.removeItem('token');
|
||||
}
|
||||
|
||||
handleRefresh = () => {
|
||||
window.location.reload();
|
||||
}
|
||||
|
||||
render() {
|
||||
const login = this.state.login;
|
||||
const user = this.state.user;
|
||||
const toolData = this.state.toolData;
|
||||
const toolStatus = this.state.toolStatus;
|
||||
const user = this.state.user;
|
||||
const connected = this.state.connected;
|
||||
const network = this.state.network;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Menu fixed='top' borderless inverted>
|
||||
<Menu.Item>
|
||||
<Icon name='bars' size='big' />
|
||||
</Menu.Item>
|
||||
<Menu.Item as={Link} to='/'>
|
||||
<Icon name='home' size='big' />
|
||||
</Menu.Item>
|
||||
<Menu.Item>
|
||||
<Icon name='circle' color={connected ? 'green' : 'red'} />
|
||||
</Menu.Item>
|
||||
<Menu.Menu position='right'>
|
||||
<Menu.Item position='right'>
|
||||
<Input transparent inverted placeholder='Search...' icon='search' />
|
||||
network ?
|
||||
<div>
|
||||
<Menu fixed='top' borderless inverted>
|
||||
<Menu.Item onClick={this.confirmLogout}>
|
||||
<Icon name='user close' size='big' />
|
||||
</Menu.Item>
|
||||
</Menu.Menu>
|
||||
</Menu>
|
||||
<div style={{height: '70px', display: 'inline-block'}} />
|
||||
<Menu.Item as={Link} to='/'>
|
||||
<Icon name='home' size='big' />
|
||||
</Menu.Item>
|
||||
<Menu.Item>
|
||||
<Icon name='circle' color={connected && toolStatus ? 'green' : 'red'} />
|
||||
{connected && toolStatus ? 'Connected' : 'Disconnected'}
|
||||
</Menu.Item>
|
||||
</Menu>
|
||||
<div style={{height: '70px', display: 'inline-block'}} />
|
||||
|
||||
<Confirm
|
||||
open={login.confirmLogout}
|
||||
header='Logout'
|
||||
onCancel={this.cancelLogout}
|
||||
onConfirm={this.handleLogout}
|
||||
/>
|
||||
|
||||
{toolData && user ?
|
||||
<div>
|
||||
<Route exact path='/' render={props =>
|
||||
<Categories {...props} data={toolData} />
|
||||
} />
|
||||
{login.token ?
|
||||
<div>
|
||||
{toolData && user ?
|
||||
<div>
|
||||
<Route exact path='/' render={props =>
|
||||
<Categories {...props} data={toolData} />
|
||||
} />
|
||||
|
||||
<Route exact path='/:category' render={props =>
|
||||
<Category {...props} data={toolData} user={user} />
|
||||
} />
|
||||
<Route exact path='/:category' render={props =>
|
||||
<Category {...props} data={toolData} user={user} />
|
||||
} />
|
||||
|
||||
<Route exact path='/:category/:id' render={props =>
|
||||
<Tool {...props}
|
||||
data={toolData}
|
||||
user={user}
|
||||
toolStatus={toolStatus}
|
||||
requestInterlock={this.requestInterlock}
|
||||
/>
|
||||
} />
|
||||
</div>
|
||||
:
|
||||
<Dimmer active>
|
||||
<Loader>Loading</Loader>
|
||||
</Dimmer>
|
||||
}
|
||||
</div>
|
||||
<Route exact path='/:category/:slug' render={props =>
|
||||
<Tool {...props}
|
||||
data={toolData}
|
||||
user={user}
|
||||
toolStatus={toolStatus}
|
||||
requestInterlock={this.requestInterlock}
|
||||
/>
|
||||
} />
|
||||
</div>
|
||||
:
|
||||
<Dimmer active>
|
||||
<Loader>Loading</Loader>
|
||||
</Dimmer>
|
||||
}
|
||||
</div>
|
||||
:
|
||||
<Container text>
|
||||
<Form size='large' onSubmit={this.handleSubmit}>
|
||||
{login.error ?
|
||||
<Message visible error header='Invalid username / password!' />
|
||||
:
|
||||
<Message visible warning header='Please log in to access the tools!' />
|
||||
}
|
||||
<Form.Field>
|
||||
<label>Protospace Username</label>
|
||||
<input name='username' placeholder='Username' value={login.username} onChange={this.handleChange} />
|
||||
</Form.Field>
|
||||
<Form.Field>
|
||||
<label>Password</label>
|
||||
<input name='password' type='password' value={login.password} onChange={this.handleChange} />
|
||||
</Form.Field>
|
||||
<Button type='submit'>Submit</Button>
|
||||
</Form>
|
||||
</Container>
|
||||
}
|
||||
</div>
|
||||
:
|
||||
<Dimmer active>
|
||||
<Header inverted icon>
|
||||
<Icon color='red' name='wifi' />
|
||||
Please connect to the "Protospace" wifi
|
||||
</Header>
|
||||
<br />
|
||||
<Button size='big' inverted icon labelPosition='left' onClick={this.handleRefresh}>
|
||||
<Icon name='refresh' />
|
||||
Refresh
|
||||
</Button>
|
||||
</Dimmer>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@@ -23,12 +23,12 @@ class Category extends Component {
|
||||
|
||||
<Item.Group link unstackable divided>
|
||||
{category.tools.map((x, n) =>
|
||||
<Item as={Link} to={'/' + category.slug + '/' + x.id} key={n}>
|
||||
<Item as={Link} to={'/' + category.slug + '/' + x.slug} key={n}>
|
||||
<Item.Image size='tiny' src={x.photo} />
|
||||
<Item.Content>
|
||||
<Item.Header>{x.name}</Item.Header>
|
||||
<Item.Description>
|
||||
{user.authorizedTools.includes(x.id) ?
|
||||
{user.profile.authorized_tools.includes(x.slug) ?
|
||||
<Label color='green'>
|
||||
<Icon name='check' /> Authorized
|
||||
</Label> : <Label color='red'>
|
||||
|
@@ -9,7 +9,7 @@ class Tool extends Component {
|
||||
} else if (status.action == 'arm') {
|
||||
return { msg: 'Arming...', canArm: false, canDisarm: true, };
|
||||
} else if (status.action == 'disarm') {
|
||||
return { msg: 'Disarming...', canArm: true, canDisarm: false, };
|
||||
return { msg: 'Disarming...', canArm: false, canDisarm: false, };
|
||||
} else if (status.state == 'off') {
|
||||
return { msg: 'Off.', canArm: true, canDisarm: false, };
|
||||
} else if (status.state == 'armed') {
|
||||
@@ -33,16 +33,14 @@ class Tool extends Component {
|
||||
);
|
||||
|
||||
const tool = category.tools.find(x =>
|
||||
x.id.toString() === match.params.id
|
||||
x.slug === match.params.slug
|
||||
);
|
||||
|
||||
const status = toolStatus.find(x =>
|
||||
x.id.toString() === match.params.id
|
||||
) || null;
|
||||
const status = toolStatus[match.params.slug] || null;
|
||||
const decodedStatus = this.decodeStatus(status);
|
||||
console.log(decodedStatus);
|
||||
|
||||
const approved = user.authorizedTools.includes(tool.id);
|
||||
const approved = user.profile.authorized_tools.includes(tool.slug);
|
||||
|
||||
return (
|
||||
<div>
|
||||
@@ -58,24 +56,25 @@ class Tool extends Component {
|
||||
<Segment>
|
||||
<Image src={tool.photo} size='medium' centered rounded />
|
||||
<Segment textAlign='center' basic>
|
||||
<p> Status: {decodedStatus.msg}</p>
|
||||
<p>Status: {decodedStatus.msg}</p>
|
||||
<div>
|
||||
<Button color='green'
|
||||
disabled={!approved || !decodedStatus.canArm}
|
||||
onClick={() => requestInterlock({toolId: tool.id, action: 'arm',})}
|
||||
>
|
||||
<Icon name='lightning' /> Arm
|
||||
</Button>
|
||||
<Button color='red'
|
||||
disabled={!approved || !decodedStatus.canDisarm}
|
||||
onClick={() => requestInterlock({toolId: tool.id, action: 'disarm',})}
|
||||
>
|
||||
<Icon name='stop' /> Disarm
|
||||
</Button>
|
||||
<Button color='green'
|
||||
disabled={!approved || !decodedStatus.canArm}
|
||||
onClick={() => requestInterlock({toolSlug: tool.slug, action: 'arm',})}
|
||||
>
|
||||
<Icon name='lightning' /> Arm
|
||||
</Button>
|
||||
<Button color='red'
|
||||
disabled={!approved || !decodedStatus.canDisarm}
|
||||
onClick={() => requestInterlock({toolSlug: tool.slug, action: 'disarm',})}
|
||||
>
|
||||
<Icon name='stop' /> Disarm
|
||||
</Button>
|
||||
<br />
|
||||
{approved || <Label basic color='red' pointing>
|
||||
Not authorized! Please take the xyz course.
|
||||
</Label>}
|
||||
</div>
|
||||
{approved || <Label basic color='red' pointing>
|
||||
Not authorized! Please take the xyz course.
|
||||
</Label>}
|
||||
</Segment>
|
||||
|
||||
<Table basic='very' unstackable>
|
||||
|
Reference in New Issue
Block a user