Began work on spying code
This commit is contained in:
@@ -4,4 +4,7 @@ _4 June 2019_
|
|||||||
|
|
||||||
* Improved the instructions.
|
* Improved the instructions.
|
||||||
* Disable attack button with no soldiers.
|
* Disable attack button with no soldiers.
|
||||||
|
* Added credentials to attack status requests (others can't spoof to see who you're attacking anymore - my bad!)
|
||||||
|
* Began work on spying infrastructure.
|
||||||
|
* Made the attack button more generic - can reuse a lot of attack code for spying code.
|
||||||
* More coming later today...
|
* More coming later today...
|
||||||
+14
-3
@@ -77,19 +77,30 @@ const attackRequest = (connection) => (req, res) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const attackStatusRequest = (connection) => (req, res) => { //TODO: proper credentials
|
const attackStatusRequest = (connection) => (req, res) => {
|
||||||
isAttacking(connection, req.body.attacker, (err, attacking, defender) => {
|
//verify the credentials
|
||||||
|
let query = 'SELECT COUNT(*) AS total FROM sessions WHERE accountId = ? AND token = ?;';
|
||||||
|
connection.query(query, [req.body.id, req.body.token], (err, results) => {
|
||||||
|
if (err) throw err;
|
||||||
|
|
||||||
|
if (results[0].total !== 1) {
|
||||||
|
res.status(400).write(log('Invalid attack status request credentials', req.body.id, req.body.token));
|
||||||
|
res.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
isAttacking(connection, req.body.id, (err, attacking, defender) => {
|
||||||
if (err) throw err;
|
if (err) throw err;
|
||||||
|
|
||||||
res.status(200).json({
|
res.status(200).json({
|
||||||
status: attacking ? 'attacking' : 'idle',
|
status: attacking ? 'attacking' : 'idle',
|
||||||
attacker: req.body.attacker,
|
|
||||||
defender: defender,
|
defender: defender,
|
||||||
msg: null
|
msg: null
|
||||||
});
|
});
|
||||||
|
|
||||||
res.end();
|
res.end();
|
||||||
});
|
});
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const combatLogRequest = (connection) => (req, res) => {
|
const combatLogRequest = (connection) => (req, res) => {
|
||||||
|
|||||||
@@ -51,6 +51,12 @@ app.post('/attackstatusrequest', combat.attackStatusRequest(connection));
|
|||||||
app.post('/combatlogrequest', combat.combatLogRequest(connection));
|
app.post('/combatlogrequest', combat.combatLogRequest(connection));
|
||||||
combat.runCombatTick(connection);
|
combat.runCombatTick(connection);
|
||||||
|
|
||||||
|
let spying = require('./spying.js');
|
||||||
|
app.post('/spyrequest', spying.spyRequest(connection));
|
||||||
|
app.post('/spystatusrequest', spying.spyStatusRequest(connection));
|
||||||
|
app.post('/spylogrequest', spying.spyLogRequest(connection));
|
||||||
|
spying.runSpyTick(connection);
|
||||||
|
|
||||||
let equipment = require('./equipment.js');
|
let equipment = require('./equipment.js');
|
||||||
app.post('/equipmentrequest', equipment.equipmentRequest(connection));
|
app.post('/equipmentrequest', equipment.equipmentRequest(connection));
|
||||||
app.post('/equipmentpurchaserequest', equipment.purchaseRequest(connection));
|
app.post('/equipmentpurchaserequest', equipment.purchaseRequest(connection));
|
||||||
|
|||||||
@@ -0,0 +1,62 @@
|
|||||||
|
//environment variables
|
||||||
|
require('dotenv').config();
|
||||||
|
|
||||||
|
//libraries
|
||||||
|
let CronJob = require('cron').CronJob;
|
||||||
|
|
||||||
|
//utilities
|
||||||
|
let { logDiagnostics } = require('./diagnostics.js');
|
||||||
|
let { log } = require('../common/utilities.js');
|
||||||
|
|
||||||
|
let { isSpying } = require('./utilities.js');
|
||||||
|
|
||||||
|
const spyRequest = (connection) => (req, res) => {
|
||||||
|
//TODO
|
||||||
|
res.status(400).write(log('Not yet implemented', 'spyRequest'));
|
||||||
|
res.end();
|
||||||
|
};
|
||||||
|
|
||||||
|
const spyStatusRequest = (connection) => (req, res) => {
|
||||||
|
//verify the credentials
|
||||||
|
let query = 'SELECT COUNT(*) AS total FROM sessions WHERE accountId = ? AND token = ?;';
|
||||||
|
connection.query(query, [req.body.id, req.body.token], (err, results) => {
|
||||||
|
if (err) throw err;
|
||||||
|
|
||||||
|
if (results[0].total !== 1) {
|
||||||
|
res.status(400).write(log('Invalid spy status request credentials', req.body.id, req.body.token));
|
||||||
|
res.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
isSpying(connection, req.body.id, (err, spying, defender) => {
|
||||||
|
if (err) throw err;
|
||||||
|
|
||||||
|
res.status(200).json({
|
||||||
|
status: spying ? 'spying' : 'idle',
|
||||||
|
attacker: req.body.attacker,
|
||||||
|
defender: defender,
|
||||||
|
msg: null
|
||||||
|
});
|
||||||
|
|
||||||
|
res.end();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const spyLogRequest = (connection) => (req, res) => {
|
||||||
|
//TODO
|
||||||
|
res.status(400).write(log('Not yet implemented', 'spyLogRequest'));
|
||||||
|
res.end();
|
||||||
|
};
|
||||||
|
|
||||||
|
const runSpyTick = (connection) => {
|
||||||
|
//TODO
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
spyRequest: spyRequest,
|
||||||
|
spyStatusRequest: spyStatusRequest,
|
||||||
|
spyLogRequest: spyLogRequest,
|
||||||
|
runSpyTick: runSpyTick
|
||||||
|
};
|
||||||
|
|
||||||
+30
-2
@@ -40,7 +40,7 @@ const isAttacking = (connection, user, cb) => {
|
|||||||
} else if (typeof(user) === 'string') {
|
} else if (typeof(user) === 'string') {
|
||||||
query = 'SELECT * FROM pendingCombat WHERE attackerId IN (SELECT id FROM accounts WHERE username = ?);';
|
query = 'SELECT * FROM pendingCombat WHERE attackerId IN (SELECT id FROM accounts WHERE username = ?);';
|
||||||
} else {
|
} else {
|
||||||
return cb(`Unknown argument type for user: ${typeof(user)}`);
|
return cb(`isAttacking: Unknown argument type for user: ${typeof(user)}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
connection.query(query, [user], (err, results) => {
|
connection.query(query, [user], (err, results) => {
|
||||||
@@ -59,8 +59,36 @@ const isAttacking = (connection, user, cb) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const isSpying = (connection, user, cb) => {
|
||||||
|
let query;
|
||||||
|
|
||||||
|
if (isNormalInteger(user)) {
|
||||||
|
query = 'SELECT * FROM pendingSpying WHERE attackerId = ?;';
|
||||||
|
} else if (typeof(user) === 'string') {
|
||||||
|
query = 'SELECT * FROM pendingSpying WHERE attackerId IN (SELECT id FROM accounts WHERE username = ?);';
|
||||||
|
} else {
|
||||||
|
return cb(`isSpying: Unknown argument type for user: ${typeof(user)}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
connection.query(query, [user], (err, results) => {
|
||||||
|
if (err) throw err;
|
||||||
|
|
||||||
|
if (results.length === 0) {
|
||||||
|
return cb(undefined, false);
|
||||||
|
} else {
|
||||||
|
//get the username of the person being spied on
|
||||||
|
let query = 'SELECT username FROM accounts WHERE id = ?;';
|
||||||
|
connection.query(query, [results[0].defenderId], (err, results) => {
|
||||||
|
if (err) throw err;
|
||||||
|
return cb(undefined, true, results[0].username);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
getStatistics: getStatistics,
|
getStatistics: getStatistics,
|
||||||
getOwned: getOwned,
|
getOwned: getOwned,
|
||||||
isAttacking: isAttacking
|
isAttacking: isAttacking,
|
||||||
|
isSpying: isSpying
|
||||||
};
|
};
|
||||||
@@ -115,6 +115,41 @@ CREATE TABLE IF NOT EXISTS pastCombat (
|
|||||||
CONSTRAINT FOREIGN KEY fk_defenderId(defenderId) REFERENCES accounts(id) ON UPDATE CASCADE ON DELETE CASCADE
|
CONSTRAINT FOREIGN KEY fk_defenderId(defenderId) REFERENCES accounts(id) ON UPDATE CASCADE ON DELETE CASCADE
|
||||||
);
|
);
|
||||||
|
|
||||||
|
#spying system
|
||||||
|
CREATE TABLE IF NOT EXISTS pendingSpying (
|
||||||
|
id INTEGER UNSIGNED AUTO_INCREMENT PRIMARY KEY UNIQUE,
|
||||||
|
td TIMESTAMP DEFAULT CURRENT_TIMESTAMP(),
|
||||||
|
|
||||||
|
eventTime TIMESTAMP,
|
||||||
|
|
||||||
|
attackerId INTEGER UNSIGNED UNIQUE,
|
||||||
|
defenderId INTEGER UNSIGNED,
|
||||||
|
attackingUnits INTEGER UNSIGNED,
|
||||||
|
|
||||||
|
CONSTRAINT FOREIGN KEY fk_attackerId(attackerId) REFERENCES accounts(id) ON UPDATE CASCADE ON DELETE CASCADE,
|
||||||
|
CONSTRAINT FOREIGN KEY fk_defenderId(defenderId) REFERENCES accounts(id) ON UPDATE CASCADE ON DELETE CASCADE
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS pastSpying (
|
||||||
|
id INTEGER UNSIGNED AUTO_INCREMENT PRIMARY KEY UNIQUE,
|
||||||
|
td TIMESTAMP DEFAULT CURRENT_TIMESTAMP(),
|
||||||
|
|
||||||
|
eventTime TIMESTAMP,
|
||||||
|
|
||||||
|
attackerId INTEGER UNSIGNED,
|
||||||
|
defenderId INTEGER UNSIGNED,
|
||||||
|
attackingUnits INTEGER UNSIGNED,
|
||||||
|
|
||||||
|
success ENUM ('success', 'failure'),
|
||||||
|
|
||||||
|
spoilsGold INTEGER,
|
||||||
|
|
||||||
|
/* check the table "equipmentStolen" for a list of equipment stolen */
|
||||||
|
|
||||||
|
CONSTRAINT FOREIGN KEY fk_attackerId(attackerId) REFERENCES accounts(id) ON UPDATE CASCADE ON DELETE CASCADE,
|
||||||
|
CONSTRAINT FOREIGN KEY fk_defenderId(defenderId) REFERENCES accounts(id) ON UPDATE CASCADE ON DELETE CASCADE
|
||||||
|
);
|
||||||
|
|
||||||
#equipment system
|
#equipment system
|
||||||
CREATE TABLE IF NOT EXISTS equipment (
|
CREATE TABLE IF NOT EXISTS equipment (
|
||||||
id INTEGER UNSIGNED AUTO_INCREMENT PRIMARY KEY UNIQUE,
|
id INTEGER UNSIGNED AUTO_INCREMENT PRIMARY KEY UNIQUE,
|
||||||
@@ -129,3 +164,18 @@ CREATE TABLE IF NOT EXISTS equipment (
|
|||||||
|
|
||||||
CONSTRAINT FOREIGN KEY fk_accountId(accountId) REFERENCES accounts(id) ON UPDATE CASCADE ON DELETE CASCADE
|
CONSTRAINT FOREIGN KEY fk_accountId(accountId) REFERENCES accounts(id) ON UPDATE CASCADE ON DELETE CASCADE
|
||||||
);
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS equipmentStolen (
|
||||||
|
id INTEGER UNSIGNED AUTO_INCREMENT PRIMARY KEY UNIQUE,
|
||||||
|
td TIMESTAMP DEFAULT CURRENT_TIMESTAMP(),
|
||||||
|
|
||||||
|
pastSpyingId INTEGER UNSIGNED,
|
||||||
|
|
||||||
|
name VARCHAR(50),
|
||||||
|
quantity INTEGER,
|
||||||
|
|
||||||
|
type VARCHAR(50),
|
||||||
|
|
||||||
|
CONSTRAINT FOREIGN KEY fk_pastSpyingId(pastSpyingId) REFERENCES pastSpying(id) ON UPDATE CASCADE ON DELETE CASCADE
|
||||||
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -233,16 +233,30 @@ class Profile extends React.Component {
|
|||||||
setWarning={this.setWarning.bind(this)}
|
setWarning={this.setWarning.bind(this)}
|
||||||
attacker={this.props.account.username}
|
attacker={this.props.account.username}
|
||||||
defender={this.props.profile.username}
|
defender={this.props.profile.username}
|
||||||
token={this.props.account.token}
|
statusRequest={'/attackstatusrequest'}
|
||||||
/>
|
attackRequest={'/attackrequest'}
|
||||||
|
pendingStatus={'attacking'}
|
||||||
|
pendingMsg={'Your soldiers are attacking'}
|
||||||
|
parseUnits={(json) => json.soldiers}
|
||||||
|
>Attack</AttackButton>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className='row'>
|
<div className='row'>
|
||||||
<p className='col'>Soldiers:</p>
|
<p className='col'>Soldiers:</p>
|
||||||
<p className='col'>{this.props.profile.soldiers}</p>
|
<p className='col'>{this.props.profile.soldiers}</p>
|
||||||
|
|
||||||
<div className='col' />
|
<AttackButton
|
||||||
<div className='col' />
|
className='col'
|
||||||
|
style={{flex: '2 1 2%'}}
|
||||||
|
setWarning={this.setWarning.bind(this)}
|
||||||
|
attacker={this.props.account.username}
|
||||||
|
defender={this.props.profile.username}
|
||||||
|
statusRequest={'/spystatusrequest'}
|
||||||
|
attackRequest={'/spyrequest'}
|
||||||
|
pendingStatus={'spying'}
|
||||||
|
pendingMsg={'Your spies are spying on'}
|
||||||
|
parseUnits={(json) => json.spies}
|
||||||
|
>Send Spies</AttackButton>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className='row'>
|
<div className='row'>
|
||||||
|
|||||||
@@ -6,11 +6,11 @@ class AttackButton extends React.Component {
|
|||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
soldiers: 0, //NOTE: not stored in profile afterall
|
units: 0,
|
||||||
message: ''
|
message: ''
|
||||||
};
|
};
|
||||||
|
|
||||||
this.sendRequest('/attackstatusrequest', {attacker: this.props.attacker}, this.attackStatus.bind(this));
|
this.sendRequest(this.props.statusRequest, {/* SO MUCH FOR DEFAULT ARGUMENTS IN NODE */}, this.attackStatus.bind(this));
|
||||||
this.sendRequest('/profilerequest', {username: this.props.attacker}, this.profileData.bind(this));
|
this.sendRequest('/profilerequest', {username: this.props.attacker}, this.profileData.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -20,22 +20,21 @@ class AttackButton extends React.Component {
|
|||||||
<p className={this.props.className} style={this.props.style}>{this.state.message}</p>
|
<p className={this.props.className} style={this.props.style}>{this.state.message}</p>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
//inject something extra
|
|
||||||
let onClick = (e) => {
|
let onClick = (e) => {
|
||||||
this.sendRequest('/attackrequest', {attacker: this.props.attacker, defender: this.props.defender}, this.attackStatus.bind(this));
|
this.sendRequest(this.props.attackRequest, {attacker: this.props.attacker, defender: this.props.defender}, this.attackStatus.bind(this));
|
||||||
if (this.props.onClick) {
|
if (this.props.onClick) {
|
||||||
this.props.onClick(e);
|
this.props.onClick(e); //inject something extra
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<button className={this.props.className} style={this.props.style} onClick={onClick} disabled={!this.state.soldiers}>Attack</button>
|
<button className={this.props.className} style={this.props.style} onClick={onClick} disabled={!this.state.units}>{this.props.children}</button>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//gameplay functions
|
//gameplay functions
|
||||||
sendRequest(url, args = {}, onSuccess) { //send a unified request, using my credentials
|
sendRequest(url, args, onSuccess) { //send a unified request, using my credentials
|
||||||
//build the XHR
|
//build the XHR
|
||||||
let xhr = new XMLHttpRequest();
|
let xhr = new XMLHttpRequest();
|
||||||
xhr.open('POST', url, true);
|
xhr.open('POST', url, true);
|
||||||
@@ -62,13 +61,13 @@ class AttackButton extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
attackStatus(json) {
|
attackStatus(json) {
|
||||||
if (json.status === 'attacking') {
|
if (json.status === this.props.pendingStatus) {
|
||||||
this.setState({ message: `Your soldiers are attacking ${json.defender}` });
|
this.setState({ message: `${this.props.pendingMsg} ${json.defender}` });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
profileData(json) {
|
profileData(json) {
|
||||||
this.setState({ soldiers: json.soldiers });
|
this.setState({units: this.props.parseUnits(json)});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -78,6 +77,11 @@ AttackButton.propTypes = {
|
|||||||
|
|
||||||
attacker: PropTypes.string.isRequired,
|
attacker: PropTypes.string.isRequired,
|
||||||
defender: PropTypes.string.isRequired,
|
defender: PropTypes.string.isRequired,
|
||||||
|
statusRequest: PropTypes.string.isRequired,
|
||||||
|
attackRequest: PropTypes.string.isRequired,
|
||||||
|
pendingStatus: PropTypes.string.isRequired,
|
||||||
|
pendingMsg: PropTypes.string.isRequired,
|
||||||
|
parseUnits: PropTypes.func.isRequired,
|
||||||
|
|
||||||
className: PropTypes.string,
|
className: PropTypes.string,
|
||||||
style: PropTypes.object,
|
style: PropTypes.object,
|
||||||
|
|||||||
@@ -30,12 +30,12 @@ class Login extends React.Component {
|
|||||||
|
|
||||||
<form action='/loginrequest' method='post' onSubmit={ this.submit.bind(this) } >
|
<form action='/loginrequest' method='post' onSubmit={ this.submit.bind(this) } >
|
||||||
<div>
|
<div>
|
||||||
<label for='email'>Email:</label>
|
<label htmlFor='email'>Email:</label>
|
||||||
<input id='email' type='text' name='email' value={this.state.email} onChange={ this.updateEmail.bind(this) } />
|
<input id='email' type='text' name='email' value={this.state.email} onChange={ this.updateEmail.bind(this) } />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label for='password'>Password:</label>
|
<label htmlFor='password'>Password:</label>
|
||||||
<input id='password' type='password' name='password' value={this.state.password} onChange={ this.updatePassword.bind(this) } />
|
<input id='password' type='password' name='password' value={this.state.password} onChange={ this.updatePassword.bind(this) } />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -30,12 +30,12 @@ class PasswordChange extends React.Component {
|
|||||||
|
|
||||||
<form action='/passwordchangerequest' method='post' onSubmit={this.submit.bind(this)}>
|
<form action='/passwordchangerequest' method='post' onSubmit={this.submit.bind(this)}>
|
||||||
<div>
|
<div>
|
||||||
<label for='password'>Password:</label>
|
<label htmlFor='password'>Password:</label>
|
||||||
<input id='password' type='password' name='password' value={this.state.password} onChange={this.updatePassword.bind(this)} />
|
<input id='password' type='password' name='password' value={this.state.password} onChange={this.updatePassword.bind(this)} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label for='retype'>Retype Password:</label>
|
<label htmlFor='retype'>Retype Password:</label>
|
||||||
<input id='retype' type='password' name='retype' value={this.state.retype} onChange={this.updateRetype.bind(this)} />
|
<input id='retype' type='password' name='retype' value={this.state.retype} onChange={this.updateRetype.bind(this)} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ class PasswordRecover extends React.Component {
|
|||||||
|
|
||||||
<form action='/passwordrecoverrequest' method='post' onSubmit={this.submit.bind(this)}>
|
<form action='/passwordrecoverrequest' method='post' onSubmit={this.submit.bind(this)}>
|
||||||
<div>
|
<div>
|
||||||
<label for='email'>Email:</label>
|
<label htmlFor='email'>Email:</label>
|
||||||
<input id='email' type='text' name='email' value={this.state.email} onChange={this.updateEmail.bind(this)} />
|
<input id='email' type='text' name='email' value={this.state.email} onChange={this.updateEmail.bind(this)} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -29,12 +29,12 @@ class PasswordReset extends React.Component {
|
|||||||
|
|
||||||
<form action='/passwordresetrequest' method='post' onSubmit={this.submit.bind(this)}>
|
<form action='/passwordresetrequest' method='post' onSubmit={this.submit.bind(this)}>
|
||||||
<div>
|
<div>
|
||||||
<label for='password'>Password:</label>
|
<label htmlFor='password'>Password:</label>
|
||||||
<input id='password' type='password' name='password' value={this.state.password} onChange={this.updatePassword.bind(this)} />
|
<input id='password' type='password' name='password' value={this.state.password} onChange={this.updatePassword.bind(this)} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label for='retype'>Retype Password:</label>
|
<label htmlFor='retype'>Retype Password:</label>
|
||||||
<input id='retype' type='password' name='retype' value={this.state.retype} onChange={this.updateRetype.bind(this)} />
|
<input id='retype' type='password' name='retype' value={this.state.retype} onChange={this.updateRetype.bind(this)} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -30,22 +30,22 @@ class Signup extends React.Component {
|
|||||||
|
|
||||||
<form action='/signuprequest' method='post' onSubmit={this.submit.bind(this)}>
|
<form action='/signuprequest' method='post' onSubmit={this.submit.bind(this)}>
|
||||||
<div>
|
<div>
|
||||||
<label for='email'>Email:</label>
|
<label htmlFor='email'>Email:</label>
|
||||||
<input id='email' type='text' name='email' value={this.state.email} onChange={this.updateEmail.bind(this)} />
|
<input id='email' type='text' name='email' value={this.state.email} onChange={this.updateEmail.bind(this)} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label for='username'>User Name:</label>
|
<label htmlFor='username'>User Name:</label>
|
||||||
<input id='username' type='text' name='username' value={this.state.username} onChange={this.updateUsername.bind(this)} />
|
<input id='username' type='text' name='username' value={this.state.username} onChange={this.updateUsername.bind(this)} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label for='password'>Password:</label>
|
<label htmlFor='password'>Password:</label>
|
||||||
<input id='password' type='password' name='password' value={this.state.password} onChange={this.updatePassword.bind(this)} />
|
<input id='password' type='password' name='password' value={this.state.password} onChange={this.updatePassword.bind(this)} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label for='retype'>Retype Password:</label>
|
<label htmlFor='retype'>Retype Password:</label>
|
||||||
<input id='retype' type='password' name='retype' value={this.state.retype} onChange={this.updateRetype.bind(this)} />
|
<input id='retype' type='password' name='retype' value={this.state.retype} onChange={this.updateRetype.bind(this)} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user