implement login
parent
ba6ed936a5
commit
298705c9c7
|
@ -36,6 +36,11 @@
|
|||
"ignoreTemplateLiterals": true
|
||||
}],
|
||||
|
||||
// disallow else after a return in an if
|
||||
// https://eslint.org/docs/rules/no-else-return
|
||||
// retropilot: allow else-if...
|
||||
"no-else-return": ["error", { "allowElseIf": true }],
|
||||
|
||||
// restrict file extensions that may contain JSX
|
||||
// https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-filename-extension.md
|
||||
// retropilot: we don't care about this
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
"axios": "^0.24.0",
|
||||
"google-map-react": "^2.1.10",
|
||||
"prop-types": "^15.8.1",
|
||||
"query-string": "^7.1.1",
|
||||
"rc-scrollbars": "^1.1.3",
|
||||
"react": "^17.0.2",
|
||||
"react-custom-scrollbars": "^4.2.1",
|
||||
|
@ -9704,6 +9705,14 @@
|
|||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/filter-obj": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/filter-obj/-/filter-obj-1.1.0.tgz",
|
||||
"integrity": "sha1-mzERErxsYSehbgFsbF1/GeCAXFs=",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/finalhandler": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
|
||||
|
@ -14632,6 +14641,26 @@
|
|||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/normalize-url/node_modules/query-string": {
|
||||
"version": "4.3.4",
|
||||
"resolved": "https://registry.npmjs.org/query-string/-/query-string-4.3.4.tgz",
|
||||
"integrity": "sha1-u7aTucqRXCMlFbIosaArYJBD2+s=",
|
||||
"dependencies": {
|
||||
"object-assign": "^4.1.0",
|
||||
"strict-uri-encode": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/normalize-url/node_modules/strict-uri-encode": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz",
|
||||
"integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/npm-run-path": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz",
|
||||
|
@ -16865,15 +16894,20 @@
|
|||
}
|
||||
},
|
||||
"node_modules/query-string": {
|
||||
"version": "4.3.4",
|
||||
"resolved": "https://registry.npmjs.org/query-string/-/query-string-4.3.4.tgz",
|
||||
"integrity": "sha1-u7aTucqRXCMlFbIosaArYJBD2+s=",
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/query-string/-/query-string-7.1.1.tgz",
|
||||
"integrity": "sha512-MplouLRDHBZSG9z7fpuAAcI7aAYjDLhtsiVZsevsfaHWDS2IDdORKbSd1kWUA+V4zyva/HZoSfpwnYMMQDhb0w==",
|
||||
"dependencies": {
|
||||
"object-assign": "^4.1.0",
|
||||
"strict-uri-encode": "^1.0.0"
|
||||
"decode-uri-component": "^0.2.0",
|
||||
"filter-obj": "^1.1.0",
|
||||
"split-on-first": "^1.0.0",
|
||||
"strict-uri-encode": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
"node": ">=6"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/querystring": {
|
||||
|
@ -19016,6 +19050,14 @@
|
|||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/split-on-first": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/split-on-first/-/split-on-first-1.1.0.tgz",
|
||||
"integrity": "sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/split-string": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz",
|
||||
|
@ -19139,11 +19181,11 @@
|
|||
"integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ=="
|
||||
},
|
||||
"node_modules/strict-uri-encode": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz",
|
||||
"integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=",
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz",
|
||||
"integrity": "sha1-ucczDHBChi9rFC3CdLvMWGbONUY=",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/string_decoder": {
|
||||
|
@ -29520,6 +29562,11 @@
|
|||
"to-regex-range": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"filter-obj": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/filter-obj/-/filter-obj-1.1.0.tgz",
|
||||
"integrity": "sha1-mzERErxsYSehbgFsbF1/GeCAXFs="
|
||||
},
|
||||
"finalhandler": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
|
||||
|
@ -33263,6 +33310,22 @@
|
|||
"prepend-http": "^1.0.0",
|
||||
"query-string": "^4.1.0",
|
||||
"sort-keys": "^1.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"query-string": {
|
||||
"version": "4.3.4",
|
||||
"resolved": "https://registry.npmjs.org/query-string/-/query-string-4.3.4.tgz",
|
||||
"integrity": "sha1-u7aTucqRXCMlFbIosaArYJBD2+s=",
|
||||
"requires": {
|
||||
"object-assign": "^4.1.0",
|
||||
"strict-uri-encode": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"strict-uri-encode": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz",
|
||||
"integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM="
|
||||
}
|
||||
}
|
||||
},
|
||||
"npm-run-path": {
|
||||
|
@ -35052,12 +35115,14 @@
|
|||
"integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ=="
|
||||
},
|
||||
"query-string": {
|
||||
"version": "4.3.4",
|
||||
"resolved": "https://registry.npmjs.org/query-string/-/query-string-4.3.4.tgz",
|
||||
"integrity": "sha1-u7aTucqRXCMlFbIosaArYJBD2+s=",
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/query-string/-/query-string-7.1.1.tgz",
|
||||
"integrity": "sha512-MplouLRDHBZSG9z7fpuAAcI7aAYjDLhtsiVZsevsfaHWDS2IDdORKbSd1kWUA+V4zyva/HZoSfpwnYMMQDhb0w==",
|
||||
"requires": {
|
||||
"object-assign": "^4.1.0",
|
||||
"strict-uri-encode": "^1.0.0"
|
||||
"decode-uri-component": "^0.2.0",
|
||||
"filter-obj": "^1.1.0",
|
||||
"split-on-first": "^1.0.0",
|
||||
"strict-uri-encode": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"querystring": {
|
||||
|
@ -36751,6 +36816,11 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"split-on-first": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/split-on-first/-/split-on-first-1.1.0.tgz",
|
||||
"integrity": "sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw=="
|
||||
},
|
||||
"split-string": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz",
|
||||
|
@ -36857,9 +36927,9 @@
|
|||
"integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ=="
|
||||
},
|
||||
"strict-uri-encode": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz",
|
||||
"integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM="
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz",
|
||||
"integrity": "sha1-ucczDHBChi9rFC3CdLvMWGbONUY="
|
||||
},
|
||||
"string_decoder": {
|
||||
"version": "1.1.1",
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
"axios": "^0.24.0",
|
||||
"google-map-react": "^2.1.10",
|
||||
"prop-types": "^15.8.1",
|
||||
"query-string": "^7.1.1",
|
||||
"rc-scrollbars": "^1.1.3",
|
||||
"react": "^17.0.2",
|
||||
"react-custom-scrollbars": "^4.2.1",
|
||||
|
|
11
src/App.js
11
src/App.js
|
@ -2,21 +2,22 @@ import React, { useState } from 'react';
|
|||
import CssBaseline from '@mui/material/CssBaseline';
|
||||
import { createTheme, ThemeProvider } from '@mui/material/styles';
|
||||
|
||||
import Login from './components/views/login';
|
||||
import UserAdmin from './components/views/useradmin';
|
||||
import { getSession } from './api/auth';
|
||||
|
||||
import Login from './components/views/Login';
|
||||
import UserAdmin from './components/views/UserAdmin';
|
||||
import GlobalSnack from './components/widgets/globalSnack';
|
||||
import DevicesProvider from './context/devices';
|
||||
import ToastProvider from './context/toast';
|
||||
import UserProvider from './context/users';
|
||||
import * as authenticationController from './controllers/authentication';
|
||||
|
||||
function App() {
|
||||
const [isAuthenticated, setAuthenticated] = useState(false);
|
||||
|
||||
authenticationController.getSession().then((session) => {
|
||||
getSession().then((session) => {
|
||||
const { authenticated } = session.data;
|
||||
setAuthenticated(authenticated);
|
||||
});
|
||||
}).catch(console.error);
|
||||
|
||||
const theme = React.useMemo(
|
||||
() => createTheme({
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
import * as request from './request';
|
||||
|
||||
export async function login(email, password) {
|
||||
const response = await request.postForm('auth/login', {
|
||||
email,
|
||||
password,
|
||||
});
|
||||
|
||||
const { success, data } = response;
|
||||
if (!success) {
|
||||
throw new Error(`Could not login: ${JSON.stringify(response)}`);
|
||||
}
|
||||
|
||||
const { jwt, user } = data;
|
||||
console.debug('Logged in as', user);
|
||||
request.setAccessToken(jwt);
|
||||
return jwt;
|
||||
}
|
||||
|
||||
export async function getSession() {
|
||||
const response = await request.get('auth/session');
|
||||
const { data } = response.data;
|
||||
return data.user;
|
||||
}
|
||||
|
||||
export async function refreshAccessToken(code, provider) {
|
||||
const resp = await request.postForm('session', {
|
||||
code,
|
||||
provider,
|
||||
});
|
||||
|
||||
const { access_token: accessToken } = resp;
|
||||
if (accessToken) {
|
||||
request.setAccessToken(accessToken);
|
||||
return accessToken;
|
||||
} else if (resp.response) {
|
||||
throw new Error(`Could not exchange oauth code for access token: response ${resp.response}`);
|
||||
} else if (resp.error) {
|
||||
throw new Error(`Could not exchange oauth code for access token: error ${resp.error}`);
|
||||
} else {
|
||||
console.warn('refreshAccessToken: unexpected response', resp);
|
||||
throw new Error('Could not exchange oauth code for access token');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
import * as request from './request';
|
||||
|
||||
export async function listDevices() {
|
||||
return request.get('devices');
|
||||
}
|
||||
|
||||
export default null;
|
|
@ -0,0 +1,56 @@
|
|||
import qs from 'query-string';
|
||||
|
||||
export default class RequestConfig {
|
||||
constructor(baseUrl = process.env.REACT_APP_API_URL) {
|
||||
this.baseUrl = `${baseUrl}${!baseUrl.endsWith('/') ? '/' : ''}api/`;
|
||||
this.defaultHeaders = {
|
||||
'Content-Type': 'application/json',
|
||||
};
|
||||
}
|
||||
|
||||
setAccessToken(accessToken) {
|
||||
if (accessToken) {
|
||||
this.defaultHeaders.Authorization = `JWT ${accessToken}`;
|
||||
}
|
||||
}
|
||||
|
||||
async request(method, path, params, dataJson = true, responseJson = true) {
|
||||
const headers = { ...this.defaultHeaders };
|
||||
if (!dataJson) {
|
||||
headers['Content-Type'] = 'application/x-www-form-urlencoded';
|
||||
}
|
||||
|
||||
let url = this.baseUrl + path;
|
||||
let body;
|
||||
if (params && Object.keys(params).length > 0) {
|
||||
if (method === 'GET' || method === 'HEAD') {
|
||||
url += `?${qs.stringify(params)}`;
|
||||
} else if (dataJson) {
|
||||
body = JSON.stringify(params);
|
||||
} else {
|
||||
body = qs.stringify(params);
|
||||
}
|
||||
}
|
||||
|
||||
console.debug(`fetch ${method} ${url}`);
|
||||
const response = await fetch(url, {
|
||||
method,
|
||||
headers,
|
||||
body,
|
||||
});
|
||||
if (!response.ok) {
|
||||
const error = await response.text();
|
||||
throw new Error(`${response.status} ${response.statusText}: ${error}`);
|
||||
} else if (!responseJson) {
|
||||
return response;
|
||||
}
|
||||
return response.json();
|
||||
}
|
||||
}
|
||||
|
||||
['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD'].forEach((method) => {
|
||||
const methodName = method.toLowerCase();
|
||||
RequestConfig.prototype[methodName] = async function (path, params, dataJson, responseJson) {
|
||||
return this.request(method, path, params, dataJson, responseJson);
|
||||
};
|
||||
});
|
|
@ -0,0 +1,31 @@
|
|||
import RequestConfig from './instance';
|
||||
|
||||
const request = new RequestConfig();
|
||||
|
||||
export function setAccessToken(accessToken) {
|
||||
request.setAccessToken(accessToken);
|
||||
}
|
||||
|
||||
export async function get(endpoint, data) {
|
||||
return request.get(endpoint, data);
|
||||
}
|
||||
|
||||
export async function post(endpoint, data) {
|
||||
return request.post(endpoint, data);
|
||||
}
|
||||
|
||||
export async function postForm(endpoint, data) {
|
||||
return request.post(endpoint, data, false);
|
||||
}
|
||||
|
||||
export async function patch(endpoint, data) {
|
||||
return request.patch(endpoint, data);
|
||||
}
|
||||
|
||||
export async function put(endpoint, data) {
|
||||
return request.put(endpoint, data);
|
||||
}
|
||||
|
||||
export async function del(endpoint, data) {
|
||||
return request.delete(endpoint, data);
|
||||
}
|
|
@ -9,22 +9,21 @@ import TextField from '@mui/material/TextField';
|
|||
import Typography from '@mui/material/Typography';
|
||||
|
||||
import { UserContext } from '../../context/users';
|
||||
import { login } from '../../api/auth';
|
||||
|
||||
export default function SignIn() {
|
||||
export default function Login() {
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [state, dispatch] = useContext(UserContext);
|
||||
console.log('component', state);
|
||||
|
||||
const handleSubmit = (event) => {
|
||||
const handleSubmit = async (event) => {
|
||||
dispatch({ type: 'toggle_button' });
|
||||
|
||||
event.preventDefault();
|
||||
const data = new FormData(event.currentTarget);
|
||||
// eslint-disable-next-line no-console
|
||||
console.log({
|
||||
email: data.get('email'),
|
||||
password: data.get('password'),
|
||||
});
|
||||
login(data.get('email'), data.get('password'))
|
||||
.then((result) => console.log('result', result))
|
||||
.catch(console.error);
|
||||
|
||||
setLoading(true);
|
||||
};
|
||||
|
@ -80,7 +79,7 @@ export default function SignIn() {
|
|||
Sign In
|
||||
</LoadingButton>
|
||||
|
||||
<Link href="#Forgot" variant="body2">
|
||||
<Link href="#forgot" variant="body2">
|
||||
New Here or Forgotten password?
|
||||
</Link>
|
||||
</Box>
|
|
@ -6,7 +6,7 @@ import React, {
|
|||
} from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import * as deviceController from '../../controllers/devices';
|
||||
import { listDevices } from '../../api/devices';
|
||||
|
||||
import ACTIONS from './actions';
|
||||
import reducer from './reducer';
|
||||
|
@ -32,11 +32,11 @@ function DevicesProvider({ children }) {
|
|||
}
|
||||
};
|
||||
|
||||
deviceController.getAllDevices().then((devices) => {
|
||||
listDevices().then((devices) => {
|
||||
console.log('devices store', devices);
|
||||
|
||||
dispatch({ type: ACTIONS.FETCH_ALL_DONGLES, data: devices });
|
||||
});
|
||||
}).catch(console.error);
|
||||
|
||||
return () => {
|
||||
// Clean up the websocket
|
||||
|
|
Loading…
Reference in New Issue