Starts adding Auth and converting to a table

This commit is contained in:
Patrick McDonagh
2017-08-18 16:34:41 -05:00
parent 6862cce9f6
commit 964e3d248c
12 changed files with 457 additions and 21 deletions

View File

@@ -1,9 +1,15 @@
import React from 'react';
import {DeviceListContainer} from './DeviceListContainer';
import {Auth} from './Auth';
export class App extends React.Component {
render(){
return <DeviceListContainer />;
return (
<div id="innerApp">
<DeviceListContainer />
</div>
);
}
}

107
app/components/Auth.js Normal file
View File

@@ -0,0 +1,107 @@
import React from 'react';
import {App} from './App';
import {baseURL} from './Meshify';
export class Auth extends React.Component{
constructor(props){
super(props);
this.state = {login: false};
this.login = this.login.bind(this);
this.logout = this.logout.bind(this);
this.getLogin = this.getLogin.bind(this);
this.handleAuthInput = this.handleAuthInput.bind(this);
}
handleAuthInput(e){
this.setState({[e.target.name]: e.target.value});
}
componentDidMount() {
this.getLogin();
}
logout(){
$.ajax({
type: 'GET',
url: baseURL + 'login',
success: function(data){
if (typeof data.username !== undefined){
this.setState({login: false, meshifyUsername: null, meshifyPassword: null});
}
}
});
}
getLogin(){
console.log("getting login");
this.setState({login: true, meshifyUsername: 'api@henry-pump.com'});
// $.ajax({
// type: 'GET',
// url: baseURL + 'login',
// success: function(data){
// console.log(data);
// if (typeof data.username !== "undefined"){
// this.setState({login: true, meshifyUsername: data.username});
// }
// }
// });
}
login(){
const authToken = btoa(this.state.meshifyUsername + ":" + this.state.meshifyPassword);
this.setState({authToken: authToken});
$.ajax({
type: 'POST',
url: baseURL + 'login',
dataType: 'json',
data: {username: this.state.meshifyUsername, authToken: authToken},
// xhrFields: {
// withCredentials: true
// },
success: function(d){
this.getLogin();
}
});
}
render() {
if(this.state.login){
return (
<div id="loggedInUser">
<div className="ui container">
<div className="ui segment">
<p>{this.state.meshifyUsername}</p>
<button className="ui button" onClick={this.logout}>Logout</button>
</div>
</div>
<App />
</div>
)
} else {
return (
<div className="ui container">
<div className="ui segment">
<div className="ui form">
<div className="fields">
<div className="field">
<label>POCloud Email</label>
<input type="email" name="meshifyUsername" onChange={this.handleAuthInput} placeholder="Email" />
</div>
<div className="field">
<label>POCloud Password</label>
<input type="password" name="meshifyPassword" onChange={this.handleAuthInput} placeholder="password" />
</div>
<div className="field">
<label>sub</label>
<button className="ui button" onClick={this.login}>Login</button>
</div>
</div>
</div>
</div>
</div>
)
}
}
}

View File

@@ -2,13 +2,13 @@ import React from 'react';
export class Channel extends React.Component {
render(){
let val = this.props.value;
if (!isNaN(parseFloat(this.props.value))){
val = Math.round(parseFloat(this.props.value) * 1000) / 1000;
}
const timestamp = new Date(this.props.timestamp * 1000);
return (
<tr>
<td>{this.props.name}</td>
<td>{this.props.value}</td>
<td>{timestamp.toLocaleString()}</td>
</tr>
<td data-tooltip={timestamp.toLocaleString()}>{val}</td>
);
}

View File

@@ -1,6 +1,7 @@
import React from 'react';
import {auth, baseURL} from './Meshify';
import {Device} from './Device';
import {MaxWaterSystem} from './MaxWaterSystem';
const hiddenDevices = ["M1", "Gateway"];
@@ -53,6 +54,9 @@ export class DeviceList extends React.Component {
return previousState;
})
}
},
error: function(e){
console.log(e);
}
})
}
@@ -79,15 +83,60 @@ export class DeviceList extends React.Component {
}
render(){
let devices = [];
for (let i in this.state.devices){
devices.push(this.rDeviceType(this.state.devices[i], i))
if (typeof this.state.devices['Advanced VFD IPP'] !== 'undefined'){
const advvfdipp = this.state.devices['Advanced VFD IPP'].map((dev, i) =>{
return (
<MaxWaterSystem key={"maxwatersystem_" + i}
deviceId={dev.id}
deviceType="Advanced VFD IPP"
name={dev.vanityName} />
);
});
return (
<div >
<h1 className="ui dividing header">Max Water System</h1>
<table className="ui sortable small celled table">
<thead>
<tr>
<th>Well</th>
<th>Status</th>
<th>Flow Yest.</th>
<th>Flow Today</th>
<th>Energy Yest.</th>
<th>Energy Today</th>
<th>Fluid Level</th>
<th>Flowrate</th>
<th>VFD Current</th>
<th>VFD Status</th>
<th>Control Mode</th>
<th>DH Status</th>
<th>Intake Pres.</th>
<th>Intake Temp.</th>
<th>Tubing Pres.</th>
</tr>
</thead>
<tbody>
{advvfdipp}
</tbody>
</table>
</div>
)
} else {
return <h1>Loading...</h1>;
}
return (
<div className="ui container">
<h1 className="ui dividing header">All Devices</h1>
{devices}
</div>
);
// let devices = [];
// for (let i in this.state.devices){
// devices.push(this.rDeviceType(this.state.devices[i], i))
// }
//
//
// return (
// <div className="ui container">
// <h1 className="ui dividing header">All Devices</h1>
// {devices}
// </div>
// );
}
}

View File

@@ -0,0 +1,87 @@
import React from 'react';
import {auth, baseURL} from './Meshify';
import {Channel} from './Channel';
let channelStarter = {
wellstatus: {order: 1, data:{}},
flowtotalyesterday: {order: 2, data:{}},
flowtotal: {order: 3, data:{}},
energytotalyesterday: {order: 4, data:{}},
energytotal: {order: 5, data:{}},
fluidlevel: {order: 6, data:{}},
flowrate: {order: 7, data:{}},
vfdcurrent: {order: 8, data:{}},
vfd_fault: {order: 9, data:{}},
pidcontrolmode: {order: 10, data:{}},
downholesensorstatus: {order: 11, data:{}},
intakepressure: {order: 12, data:{}},
intaketemperature: {order: 13, data:{}},
tubingpressure: {order: 14, data:{}},
}
export class MaxWaterSystem extends React.Component {
constructor(props){
super(props);
this.state = {channels: channelStarter};
this.getChannels = this.getChannels.bind(this);
}
componentDidMount() {
this.getChannels();
}
getChannels(){
let t = this;
const deviceId = this.props.deviceId;
$.ajax({
type: "GET",
dataType: 'json',
url: baseURL + 'devices/' + deviceId + '/values',
beforeSend: function (xhr) {
xhr.setRequestHeader("Authorization", auth.authType + " " + auth.token);
},
success: function(data){
let channels = [];
for (var c in data){
if (typeof t.state.channels[c] !== 'undefined'){
let newChan = {};
newChan.name = c;
newChan.timestamp = data[c].timestamp;
newChan.value = data[c].value;
t.setState((previousState) => {
previousState.channels[newChan.name].data = newChan;
return previousState;
})
}
}
}
})
}
render(){
const deviceName = this.props.name;
const deviceType = this.props.deviceType;
const deviceId = this.props.deviceId;
const channels = this.state.channels;
const channelList = Object.keys(channels).sort((a, b) => {
return this.state.channels[a].order - this.state.channels[b].order;
}).map(function(ch, i){
return <Channel key={deviceId + "_channel_" + i}
name={channels[ch].data.name}
timestamp={channels[ch].data.timestamp}
value={channels[ch].data.value} />
});
return (
<tr>
<td>{deviceName}</td>
{channelList}
</tr>
);
}
}

View File

@@ -12,4 +12,5 @@ export const auth = {
}
// export const baseURL = "https://henrypump.meshify.com/api/v3/";
export const baseURL = "http://localhost:3000/"
// export const baseURL = "http://localhost:3000/"
export const baseURL = "http://api.henrypump.cloud:3000/"

View File

@@ -2,6 +2,7 @@
<head>
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.2.11/semantic.min.css"></link>
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<script src="http://semantic-ui.com/javascript/library/tablesort.js"></script>
</head>
<body>
<div id="app"></div>

View File

@@ -5,6 +5,6 @@
import React from 'react';
import ReactDOM from 'react-dom';
import {App} from './components/App'
import {Auth} from './components/Auth'
ReactDOM.render(<App />, document.getElementById('app'));
ReactDOM.render(<Auth />, document.getElementById('app'));

View File

@@ -1,19 +1,55 @@
var express = require('express');
var app = express();
var cors = require('cors');
var session = require('express-session');
var morgan = require('morgan');
var bodyParser = require('body-parser');
var redis = require("redis");
var RedisStore = require('connect-redis')(session);
app.use(express.static(__dirname + "/public"));
app.use(morgan('dev'));
app.use(cors());
var client = redis.createClient();
const redisOptions = { host: 'localhost', port: 6379, client: client,ttl : 260};
// app.use(session({
// secret: 'henrypump2',
// store: new RedisStore(redisOptions),
// resave: false,
// saveUninitialized: true
// }))
var sessionStore = new session.MemoryStore();
app.use(session({
secret: 'secret',
store: sessionStore,
resave: false,
saveUninitialized: false,
proxy: undefined,
cookie: {
secure: true,
maxAge: 36000000
},
rolling: true,
unset: 'destroy'
}));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: true
}));
app.get('/', require('./routes').index);
app.get('/deviceTypes', require('./routes').deviceTypes);
app.get('/devices/:deviceId/values', require('./routes').channelValues)
app.get('/devices', require('./routes').devices);
app.post('/login', require('./routes').login);
app.get('/login', require('./routes').getLogin);
app.get('/logout', require('./routes').logout);
app.listen(3000, function () {
console.log('Listening on port 3000!')

120
server/package-lock.json generated
View File

@@ -23,6 +23,52 @@
"resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-1.1.0.tgz",
"integrity": "sha1-RSIe5Cn37h5QNb4/UVM/HN/SmIQ="
},
"body-parser": {
"version": "1.17.2",
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.17.2.tgz",
"integrity": "sha1-+IkqvI+eYn1Crtr7yma/WrmRBO4=",
"requires": {
"bytes": "2.4.0",
"content-type": "1.0.2",
"debug": "2.6.7",
"depd": "1.1.1",
"http-errors": "1.6.2",
"iconv-lite": "0.4.15",
"on-finished": "2.3.0",
"qs": "6.4.0",
"raw-body": "2.2.0",
"type-is": "1.6.15"
},
"dependencies": {
"debug": {
"version": "2.6.7",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.7.tgz",
"integrity": "sha1-krrR9tBbu2u6Isyoi80OyJTChh4=",
"requires": {
"ms": "2.0.0"
}
},
"qs": {
"version": "6.4.0",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.4.0.tgz",
"integrity": "sha1-E+JtKK1rD/qpExLNO/cI7TUecjM="
}
}
},
"bytes": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/bytes/-/bytes-2.4.0.tgz",
"integrity": "sha1-fZcZb51br39pNeJZhVSe3SpsIzk="
},
"connect-redis": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/connect-redis/-/connect-redis-3.3.0.tgz",
"integrity": "sha1-yVEMGlZ/9xDrJRDmp1CfqSsiMt8=",
"requires": {
"debug": "2.6.8",
"redis": "2.8.0"
}
},
"content-disposition": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz",
@@ -52,6 +98,11 @@
"vary": "1.1.1"
}
},
"crc": {
"version": "3.4.4",
"resolved": "https://registry.npmjs.org/crc/-/crc-3.4.4.tgz",
"integrity": "sha1-naHpgOO9RPxck79as9ozeNheRms="
},
"debug": {
"version": "2.6.8",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz",
@@ -75,6 +126,11 @@
"resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
"integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
},
"double-ended-queue": {
"version": "2.1.0-0",
"resolved": "https://registry.npmjs.org/double-ended-queue/-/double-ended-queue-2.1.0-0.tgz",
"integrity": "sha1-ED01J/0xUo9AGIEwyEHv3XgmTlw="
},
"ee-first": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
@@ -130,6 +186,22 @@
"vary": "1.1.1"
}
},
"express-session": {
"version": "1.15.5",
"resolved": "https://registry.npmjs.org/express-session/-/express-session-1.15.5.tgz",
"integrity": "sha512-BBVy6E/XqjB507wqe5T+7Ia2N/gtur/dT/fKmvGGKQqUrzI4dcBPGJgV4t2ciX7FoxZPhZcKTDTmb4+5nCyQOw==",
"requires": {
"cookie": "0.3.1",
"cookie-signature": "1.0.6",
"crc": "3.4.4",
"debug": "2.6.8",
"depd": "1.1.1",
"on-headers": "1.0.1",
"parseurl": "1.3.1",
"uid-safe": "2.1.5",
"utils-merge": "1.0.0"
}
},
"finalhandler": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.0.4.tgz",
@@ -165,6 +237,11 @@
"statuses": "1.3.1"
}
},
"iconv-lite": {
"version": "0.4.15",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.15.tgz",
"integrity": "sha1-/iZaIYrGpXz+hUkn6dBMGYJe3es="
},
"inherits": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
@@ -272,11 +349,46 @@
"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.0.tgz",
"integrity": "sha512-fjVFjW9yhqMhVGwRExCXLhJKrLlkYSaxNWdyc9rmHlrVZbk35YHH312dFd7191uQeXkI3mKLZTIbSvIeFwFemg=="
},
"random-bytes": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz",
"integrity": "sha1-T2ih3Arli9P7lYSMMDJNt11kNgs="
},
"range-parser": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz",
"integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4="
},
"raw-body": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.2.0.tgz",
"integrity": "sha1-mUl2z2pQlqQRYoQEkvC9xdbn+5Y=",
"requires": {
"bytes": "2.4.0",
"iconv-lite": "0.4.15",
"unpipe": "1.0.0"
}
},
"redis": {
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/redis/-/redis-2.8.0.tgz",
"integrity": "sha512-M1OkonEQwtRmZv4tEWF2VgpG0JWJ8Fv1PhlgT5+B+uNq2cA3Rt1Yt/ryoR+vQNOQcIEgdCdfH0jr3bDpihAw1A==",
"requires": {
"double-ended-queue": "2.1.0-0",
"redis-commands": "1.3.1",
"redis-parser": "2.6.0"
}
},
"redis-commands": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/redis-commands/-/redis-commands-1.3.1.tgz",
"integrity": "sha1-gdgm9F+pyLIBH0zXoP5ZfSQdRCs="
},
"redis-parser": {
"version": "2.6.0",
"resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-2.6.0.tgz",
"integrity": "sha1-Uu0J2srBCPGmMcB+m2mUHnoZUEs="
},
"send": {
"version": "0.15.4",
"resolved": "https://registry.npmjs.org/send/-/send-0.15.4.tgz",
@@ -327,6 +439,14 @@
"mime-types": "2.1.16"
}
},
"uid-safe": {
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz",
"integrity": "sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==",
"requires": {
"random-bytes": "1.0.0"
}
},
"unpipe": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",

View File

@@ -9,9 +9,13 @@
"author": "Patrick McDonagh",
"license": "ISC",
"dependencies": {
"body-parser": "^1.17.2",
"connect-redis": "^3.3.0",
"cors": "^2.8.4",
"deep-copy": "^1.3.0",
"express": "^4.15.4",
"morgan": "^1.8.2"
"express-session": "^1.15.5",
"morgan": "^1.8.2",
"redis": "^2.8.0"
}
}

View File

@@ -14,7 +14,32 @@ exports.index = function(req, res){
res.render('index', { });
};
exports.login = function(req, res){
console.log(req.body);
console.log("# Username set to "+ req.body.username);
req.session.username = req.body.username;
req.session.authorization = req.body.authToken;
req.session.save();
console.log("# Session value set");
console.log(req.session);
res.end();
}
exports.getLogin = function(req, res){
console.log("in getLogin, session is");
console.log(req.session);
console.log("# Client Username check "+ req.session.username);
res.json({username: req.session.username});
}
exports.logout = function(req, res){
req.session.destroy();
res.end();
}
exports.deviceTypes = function(req, res){
console.log(req.headers.authorization);
if (typeof req.headers['authorization'] !== 'undefined'){
let options = dcopy(meshifyOptions);
options.path += "devicetypes";