Persistent session

This commit is contained in:
dbroqua 2018-09-09 23:11:27 +02:00
parent c4f0a9ea62
commit 84c5fe0a6c
12 changed files with 432 additions and 249 deletions

76
package-lock.json generated
View file

@ -37,6 +37,41 @@
}
}
},
"@types/cookie": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.3.1.tgz",
"integrity": "sha512-64Uv+8bTRVZHlbB8eXQgMP9HguxPgnOOIYrQpwHWrtLDrtcG/lILKhUl7bV65NSOIJ9dXGYD7skQFXzhL8tk1A=="
},
"@types/hoist-non-react-statics": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.0.1.tgz",
"integrity": "sha512-3wTz66vV+WatOAjMST+hKCmo01KYPFgnsu+QeLcn0FuwPCoymX6aj1a4RvFCdVsfh2m0hfTPhE/zTv4M28ho1Q==",
"requires": {
"@types/react": "*"
}
},
"@types/object-assign": {
"version": "4.0.30",
"resolved": "https://registry.npmjs.org/@types/object-assign/-/object-assign-4.0.30.tgz",
"integrity": "sha1-iUk3HVqZ9Dge4PHfCpt6GH4H5lI="
},
"@types/prop-types": {
"version": "15.5.5",
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.5.5.tgz",
"integrity": "sha512-mOrlCEdwX3seT3n0AXNt4KNPAZZxcsABUHwBgFXOt+nvFUXkxCAO6UBJHPrDxWEa2KDMil86355fjo8jbZ+K0Q==",
"requires": {
"@types/react": "*"
}
},
"@types/react": {
"version": "16.4.13",
"resolved": "https://registry.npmjs.org/@types/react/-/react-16.4.13.tgz",
"integrity": "sha512-a2Z7UmwnAzZ23bTHV6on141S8vvSC7MEJGG85R5/VG80ybzkt5QJqNzlaJ0Y6OX1dncrXFW8B0vWPIx7QuOUqA==",
"requires": {
"@types/prop-types": "*",
"csstype": "^2.2.0"
}
},
"abab": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/abab/-/abab-1.0.4.tgz",
@ -2669,6 +2704,11 @@
"cssom": "0.3.x"
}
},
"csstype": {
"version": "2.5.6",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-2.5.6.tgz",
"integrity": "sha512-tKPyhy0FmfYD2KQYXD5GzkvAYLYj96cMLXr648CKGd3wBe0QqoPipImjGiLze9c8leJK8J3n7ap90tpk3E6HGQ=="
},
"currently-unhandled": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz",
@ -8639,6 +8679,26 @@
"schedule": "^0.3.0"
}
},
"react-cookie": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/react-cookie/-/react-cookie-3.0.4.tgz",
"integrity": "sha512-WNf1LifcjRQfg/QEDYQkey78XNJ46/k+lhoKrTK1Iv1jiqInl5jmjRBnEqDJ32HhgeL0iJAsJrEC+o+LkJ/O9Q==",
"requires": {
"@types/hoist-non-react-statics": "^3.0.1",
"hoist-non-react-statics": "^3.0.0",
"universal-cookie": "^3.0.4"
},
"dependencies": {
"hoist-non-react-statics": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.0.1.tgz",
"integrity": "sha512-1kXwPsOi0OGQIZNVMPvgWJ9tSnGMiMfJdihqEzrPEXlHOBh9AAHXX/QYmAJTXztnz/K+PQ8ryCb4eGaN6HlGbQ==",
"requires": {
"react-is": "^16.3.2"
}
}
}
},
"react-dev-utils": {
"version": "5.0.2",
"resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-5.0.2.tgz",
@ -8685,6 +8745,11 @@
"resolved": "https://registry.npmjs.org/react-icons/-/react-icons-3.0.5.tgz",
"integrity": "sha512-gNOTMhB3QCFsDnBkO0psdcz84BjprjT95pX6SSJ9pNARQozTsBqOKeVl+uw8zMIBGGDX9GpdY9TflnRjiX4z1A=="
},
"react-is": {
"version": "16.5.0",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.5.0.tgz",
"integrity": "sha512-kpkCGLsChXTEQJVmowQqHpCjHKJFwB4SIChYaaaiAkq8OtE2aBg5pQe8/xnFlGmz9KmMx1H4oQRUyxP7qC9v5A=="
},
"react-lifecycles-compat": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz",
@ -10599,6 +10664,17 @@
"crypto-random-string": "^1.0.0"
}
},
"universal-cookie": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/universal-cookie/-/universal-cookie-3.0.4.tgz",
"integrity": "sha512-3rhx6RAIuRmCWJttnbgzMrp2TbHhUmgQ2GrpY/US03Siv5T28iXr2qYw1m3YqmluBxEyrvZaloVemkLSId+Oyg==",
"requires": {
"@types/cookie": "^0.3.1",
"@types/object-assign": "^4.0.30",
"cookie": "^0.3.1",
"object-assign": "^4.1.0"
}
},
"universalify": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",

View file

@ -6,6 +6,7 @@
"axios": "^0.18.0",
"bootstrap": "^4.1.3",
"react": "^16.5.0",
"react-cookie": "^3.0.4",
"react-dom": "^16.5.0",
"react-icons": "^3.0.5",
"react-router-dom": "^4.3.1",
@ -14,7 +15,7 @@
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"build": "react-scripts build && ssh guarda 'rm -r www/darkou.fr/cfa/bo/static' && scp -r build/* guarda:www/darkou.fr/cfa/bo",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"
},

View file

@ -1,9 +1,15 @@
import axios from 'axios';
axios.defaults.headers.common['Access-Control-Allow-Origin'] = '*';
export function setDefaults(params) {
axios.defaults.headers.common.Authorization = params.Authorization;
}
export function setAuthorization(Authorization) {
axios.defaults.headers.common.Authorization = Authorization;
}
export default axios.create({
baseURL: 'https://api.cfa.darkou.fr/api/',
});

View file

@ -9,6 +9,7 @@ import Vegetable from './Vegetable';
import requireAuth from './requireAuth';
import Login from './Login';
import Logout from './Logout';
import './App.css';
@ -19,6 +20,7 @@ class App extends Component {
<Router>
<Switch>
<Route exact path="/" component={requireAuth(Login, false)} />
<Route exact path="/LogOut" component={Logout} />
<Route exact path="/categories" component={requireAuth(Categories)} />
<Route exact path="/categories/:categoryId" component={requireAuth(Category)} />
<Route exact path="/categories/:categoryId/vegetables/:vegetableId" component={requireAuth(Vegetable)} />

View file

@ -9,6 +9,7 @@ import {
} from 'reactstrap';
import { FaTrashAlt, FaPlus } from 'react-icons/fa';
import { Link } from 'react-router-dom';
import Navigation from './Navigation';
import Header from './Header';
import API from './Api';
@ -81,8 +82,10 @@ class Categories extends Component {
render() {
return (
<Container>
<div>
<Header />
<Container>
<Navigation />
<Table>
<thead>
<tr>
@ -123,6 +126,7 @@ Ajouter
</Button>
</Form>
</Container>
</div>
);
}
}

View file

@ -9,6 +9,7 @@ import {
} from 'reactstrap';
import { FaTrashAlt, FaPlus, FaEdit } from 'react-icons/fa';
import { Link } from 'react-router-dom';
import Navigation from './Navigation';
import Header from './Header';
import API from './Api';
@ -111,8 +112,10 @@ class Category extends Component {
render() {
return (
<div>
<Header />
<Container>
<Header categoryId={this.state.categoryId} categoryName={this.state.Category.name} />
<Navigation categoryId={this.state.categoryId} categoryName={this.state.Category.name} />
<Form inline onSubmit={this.updateCategory} style={{ marginBottom: '16px' }}>
<FormGroup className="mb-8 mr-sm-8 mb-sm-0">
<Input
@ -166,6 +169,7 @@ Ajouter
</Button>
</Form>
</Container>
</div>
);
}
}

View file

@ -1,77 +1,51 @@
import React from 'react';
import { Breadcrumb, BreadcrumbItem } from 'reactstrap';
import { Link } from 'react-router-dom';
import API from './Api';
import {
Collapse,
Navbar,
NavbarToggler,
NavbarBrand,
Nav,
NavItem,
NavLink,
} from 'reactstrap';
import { FaSignOutAlt } from 'react-icons/fa';
class Header extends React.Component {
export default class Example extends React.Component {
constructor(props) {
super(props);
const Breadcrumb = [];
if (API.defaults.headers.common.Authorization !== undefined) {
Breadcrumb.push({
name: 'Catégories',
path: '/categories',
active: !this.props.categoryId,
});
if (this.props.categoryId) {
Breadcrumb.push({
name: this.props.categoryId,
path: `/categories/${this.props.categoryId}`,
active: !this.props.vegetableId,
});
if (this.props.vegetableId) {
Breadcrumb.push({
name: this.props.vegetableId,
path: `/categories/${this.props.categoryId}/vegetal/${this.props.vegetableId}`,
active: true,
});
}
}
}
this.toggle = this.toggle.bind(this);
this.state = {
Breadcrumb,
isOpen: false,
};
}
componentWillReceiveProps(props) {
if (props.categoryName) {
const Breadcrumb = this.state.Breadcrumb;
Breadcrumb[1].name = props.categoryName;
this.setState({ Breadcrumb });
}
if (props.vegetableName) {
const Breadcrumb = this.state.Breadcrumb;
Breadcrumb[2].name = props.vegetableName;
this.setState({ Breadcrumb });
}
toggle() {
this.setState({
isOpen: !this.state.isOpen,
});
}
render() {
return (
<div>
<Breadcrumb>
{ this.state.Breadcrumb.map((item, key) => (
item.active === true
? (
<BreadcrumbItem key={key} active>
{item.name}
</BreadcrumbItem>
)
: (
<BreadcrumbItem key={key}>
<Link to={item.path}>{item.name}</Link>
</BreadcrumbItem>
)
))}
</Breadcrumb>
<Navbar color="light" light expand="md">
<NavbarBrand>RodiVert</NavbarBrand>
<NavbarToggler onClick={this.toggle} />
<Collapse isOpen={this.state.isOpen} navbar>
<Nav className="ml-auto" navbar>
<NavItem>
<NavLink tag={Link} to="/LogOut">
<FaSignOutAlt />
{' '}
Déconnexion
</NavLink>
</NavItem>
</Nav>
</Collapse>
</Navbar>
</div>
);
}
}
export default Header;

View file

@ -10,7 +10,8 @@ import {
Alert,
} from 'reactstrap';
import { FaSignInAlt } from 'react-icons/fa';
import API, { setDefaults } from './Api';
import { Cookies } from 'react-cookie';
import API, { setAuthorization } from './Api';
class Login extends Component {
constructor(props) {
@ -37,9 +38,11 @@ class Login extends Component {
})
.then((response) => {
if (response.status === 200) {
setDefaults({
Authorization: `Basic ${new Buffer(`${this.state.email}:${this.state.password}`).toString('base64')}`,
});
const cookies = new Cookies();
const Authorization = `Basic ${new Buffer(`${this.state.email}:${this.state.password}`).toString('base64')}`;
cookies.set('cfa_bo', Authorization);
setAuthorization(Authorization);
this.setState({ message: '' });
this.props.history.push('/categories');
} else {

23
src/Logout.js Normal file
View file

@ -0,0 +1,23 @@
import { Component } from 'react';
import { Cookies } from 'react-cookie';
import { setAuthorization } from './Api';
class Logout extends Component {
constructor(props) {
super(props);
const cookies = new Cookies();
setAuthorization(null);
cookies.remove('cfa_bo');
this.props.history.push('/');
}
render() {
return (
'Bye !'
);
}
}
export default Logout;

77
src/Navigation.js Normal file
View file

@ -0,0 +1,77 @@
import React from 'react';
import { Breadcrumb, BreadcrumbItem } from 'reactstrap';
import { Link } from 'react-router-dom';
import API from './Api';
class Navigation extends React.Component {
constructor(props) {
super(props);
const Breadcrumb = [];
if (API.defaults.headers.common.Authorization !== undefined) {
Breadcrumb.push({
name: 'Catégories',
path: '/categories',
active: !this.props.categoryId,
});
if (this.props.categoryId) {
Breadcrumb.push({
name: this.props.categoryId,
path: `/categories/${this.props.categoryId}`,
active: !this.props.vegetableId,
});
if (this.props.vegetableId) {
Breadcrumb.push({
name: this.props.vegetableId,
path: `/categories/${this.props.categoryId}/vegetal/${this.props.vegetableId}`,
active: true,
});
}
}
}
this.state = {
Breadcrumb,
};
}
componentWillReceiveProps(props) {
if (props.categoryName) {
const Breadcrumb = this.state.Breadcrumb;
Breadcrumb[1].name = props.categoryName;
this.setState({ Breadcrumb });
}
if (props.vegetableName) {
const Breadcrumb = this.state.Breadcrumb;
Breadcrumb[2].name = props.vegetableName;
this.setState({ Breadcrumb });
}
}
render() {
return (
<div>
<Breadcrumb>
{ this.state.Breadcrumb.map((item, key) => (
item.active === true
? (
<BreadcrumbItem key={key} active>
{item.name}
</BreadcrumbItem>
)
: (
<BreadcrumbItem key={key}>
<Link to={item.path}>{item.name}</Link>
</BreadcrumbItem>
)
))}
</Breadcrumb>
</div>
);
}
}
export default Navigation;

View file

@ -10,6 +10,7 @@ import {
Input,
} from 'reactstrap';
import { FaEdit, FaMapMarkerAlt } from 'react-icons/fa';
import Navigation from './Navigation';
import Header from './Header';
import API from './Api';
@ -161,8 +162,10 @@ class Vegetable extends Component {
}
return (
<div>
<Header />
<Container className="Vegetable">
<Header categoryId={this.state.Vegetable.Type ? this.state.Vegetable.Type.id : 1} categoryName={this.state.Vegetable.Type ? this.state.Vegetable.Type.name : null} vegetableId={this.state.Vegetable.id || 1} vegetableName={this.state.Vegetable.name} />
<Navigation categoryId={this.state.Vegetable.Type ? this.state.Vegetable.Type.id : 1} categoryName={this.state.Vegetable.Type ? this.state.Vegetable.Type.name : null} vegetableId={this.state.Vegetable.id || 1} vegetableName={this.state.Vegetable.name} />
<Form onSubmit={this.updateVegetable}>
<Row>
<Col xs={12} sm={4}>
@ -255,6 +258,7 @@ Mettre à jour
</Button>
</Form>
</Container>
</div>
);
}
}

View file

@ -1,10 +1,19 @@
import React from 'react';
import ReactDOM from 'react-dom';
import { Cookies } from 'react-cookie';
import App from './App';
import registerServiceWorker from './registerServiceWorker';
import { setAuthorization } from './Api';
import './index.css';
import 'bootstrap/dist/css/bootstrap.min.css';
const cookies = new Cookies();
const auth = cookies.get('cfa_bo');
if (auth) {
setAuthorization(auth);
}
ReactDOM.render(<App />, document.getElementById('root'));
registerServiceWorker();