verification: check if server is running (#4140)

* verification: check if server is running

See also ethcore/email-verification#67c6466 and ethcore/sms-verification#a585e42.

* verification: show in the UI if server is running

* verification: code style , more i18n

* fix i18n key
This commit is contained in:
Jannis Redmann 2017-01-13 09:51:25 +01:00 committed by Gav Wood
parent 3d06456fa5
commit 6f1c55ef5d
7 changed files with 169 additions and 25 deletions

View File

@ -16,6 +16,19 @@
import { stringify } from 'querystring'; import { stringify } from 'querystring';
export const isServerRunning = (isTestnet = false) => {
const port = isTestnet ? 28443 : 18443;
return fetch(`https://email-verification.parity.io:${port}/health`, {
mode: 'cors', cache: 'no-store'
})
.then((res) => {
return res.ok;
})
.catch(() => {
return false;
});
};
export const postToServer = (query, isTestnet = false) => { export const postToServer = (query, isTestnet = false) => {
const port = isTestnet ? 28443 : 18443; const port = isTestnet ? 28443 : 18443;
query = stringify(query); query = stringify(query);

View File

@ -16,6 +16,19 @@
import { stringify } from 'querystring'; import { stringify } from 'querystring';
export const isServerRunning = (isTestnet = false) => {
const port = isTestnet ? 8443 : 443;
return fetch(`https://sms-verification.parity.io:${port}/health`, {
mode: 'cors', cache: 'no-store'
})
.then((res) => {
return res.ok;
})
.catch(() => {
return false;
});
};
export const postToServer = (query, isTestnet = false) => { export const postToServer = (query, isTestnet = false) => {
const port = isTestnet ? 8443 : 443; const port = isTestnet ? 8443 : 443;
query = stringify(query); query = stringify(query);

View File

@ -15,6 +15,7 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
import React, { Component, PropTypes } from 'react'; import React, { Component, PropTypes } from 'react';
import { FormattedMessage } from 'react-intl';
import BigNumber from 'bignumber.js'; import BigNumber from 'bignumber.js';
import { Checkbox } from 'material-ui'; import { Checkbox } from 'material-ui';
import InfoIcon from 'material-ui/svg-icons/action/info-outline'; import InfoIcon from 'material-ui/svg-icons/action/info-outline';
@ -33,10 +34,11 @@ import styles from './gatherData.css';
export default class GatherData extends Component { export default class GatherData extends Component {
static propTypes = { static propTypes = {
fee: React.PropTypes.instanceOf(BigNumber), fee: React.PropTypes.instanceOf(BigNumber),
method: PropTypes.string.isRequired,
fields: PropTypes.array.isRequired, fields: PropTypes.array.isRequired,
isVerified: nullableProptype(PropTypes.bool.isRequired),
hasRequested: nullableProptype(PropTypes.bool.isRequired), hasRequested: nullableProptype(PropTypes.bool.isRequired),
isServerRunning: nullableProptype(PropTypes.bool.isRequired),
isVerified: nullableProptype(PropTypes.bool.isRequired),
method: PropTypes.string.isRequired,
setConsentGiven: PropTypes.func.isRequired setConsentGiven: PropTypes.func.isRequired
} }
@ -48,13 +50,19 @@ export default class GatherData extends Component {
return ( return (
<Form> <Form>
{ howItWorks } { howItWorks }
{ this.renderServerRunning() }
{ this.renderFee() } { this.renderFee() }
{ this.renderCertified() } { this.renderCertified() }
{ this.renderRequested() } { this.renderRequested() }
{ this.renderFields() } { this.renderFields() }
<Checkbox <Checkbox
className={ styles.spacing } className={ styles.spacing }
label={ 'I agree to the terms and conditions below.' } label={
<FormattedMessage
id='ui.verification.gatherData.termsOfService'
defaultMessage='I agree to the terms and conditions below.'
/>
}
disabled={ isVerified } disabled={ isVerified }
onCheck={ this.consentOnChange } onCheck={ this.consentOnChange }
/> />
@ -63,6 +71,44 @@ export default class GatherData extends Component {
); );
} }
renderServerRunning () {
const { isServerRunning } = this.props;
if (isServerRunning) {
return (
<div className={ styles.container }>
<SuccessIcon />
<p className={ styles.message }>
<FormattedMessage
id='ui.verification.gatherData.isServerRunning.true'
defaultMessage='The verification server is running.'
/>
</p>
</div>
);
} else if (isServerRunning === false) {
return (
<div className={ styles.container }>
<ErrorIcon />
<p className={ styles.message }>
<FormattedMessage
id='ui.verification.gatherData.isServerRunning.false'
defaultMessage='The verification server is not running.'
/>
</p>
</div>
);
}
return (
<p className={ styles.message }>
<FormattedMessage
id='ui.verification.gatherData.isServerRunning.pending'
defaultMessage='Checking if the verification server is running…'
/>
</p>
);
}
renderFee () { renderFee () {
const { fee } = this.props; const { fee } = this.props;
@ -72,7 +118,15 @@ export default class GatherData extends Component {
return ( return (
<div className={ styles.container }> <div className={ styles.container }>
<InfoIcon /> <InfoIcon />
<p className={ styles.message }>The fee is { fromWei(fee).toFixed(3) } ETH.</p> <p className={ styles.message }>
<FormattedMessage
id='ui.verification.gatherData.fee'
defaultMessage='The fee is {amount} ETH.'
values={ {
amount: fromWei(fee).toFixed(3)
} }
/>
</p>
</div> </div>
); );
} }
@ -84,19 +138,34 @@ export default class GatherData extends Component {
return ( return (
<div className={ styles.container }> <div className={ styles.container }>
<ErrorIcon /> <ErrorIcon />
<p className={ styles.message }>Your account is already verified.</p> <p className={ styles.message }>
<FormattedMessage
id='ui.verification.gatherData.isVerified.true'
defaultMessage='Your account is already verified.'
/>
</p>
</div> </div>
); );
} else if (isVerified === false) { } else if (isVerified === false) {
return ( return (
<div className={ styles.container }> <div className={ styles.container }>
<SuccessIcon /> <SuccessIcon />
<p className={ styles.message }>Your account is not verified yet.</p> <p className={ styles.message }>
<FormattedMessage
id='ui.verification.gatherData.isVerified.false'
defaultMessage='Your account is not verified yet.'
/>
</p>
</div> </div>
); );
} }
return ( return (
<p className={ styles.message }>Checking if your account is verified</p> <p className={ styles.message }>
<FormattedMessage
id='ui.verification.gatherData.isVerified.pending'
defaultMessage='Checking if your account is verified…'
/>
</p>
); );
} }
@ -112,19 +181,34 @@ export default class GatherData extends Component {
return ( return (
<div className={ styles.container }> <div className={ styles.container }>
<InfoIcon /> <InfoIcon />
<p className={ styles.message }>You already requested verification.</p> <p className={ styles.message }>
<FormattedMessage
id='ui.verification.gatherData.hasRequested.true'
defaultMessage='You already requested verification.'
/>
</p>
</div> </div>
); );
} else if (hasRequested === false) { } else if (hasRequested === false) {
return ( return (
<div className={ styles.container }> <div className={ styles.container }>
<SuccessIcon /> <SuccessIcon />
<p className={ styles.message }>You did not request verification yet.</p> <p className={ styles.message }>
<FormattedMessage
id='ui.verification.gatherData.hasRequested.false'
defaultMessage='You did not request verification yet.'
/>
</p>
</div> </div>
); );
} }
return ( return (
<p className={ styles.message }>Checking if you requested verification</p> <p className={ styles.message }>
<FormattedMessage
id='ui.verification.gatherData.hasRequested.pending'
defaultMessage='Checking if you requested verification…'
/>
</p>
); );
} }

View File

@ -21,7 +21,7 @@ import EmailVerificationABI from '~/contracts/abi/email-verification.json';
import VerificationStore, { import VerificationStore, {
LOADING, QUERY_DATA, QUERY_CODE, POSTED_CONFIRMATION, DONE LOADING, QUERY_DATA, QUERY_CODE, POSTED_CONFIRMATION, DONE
} from './store'; } from './store';
import { postToServer } from '../../3rdparty/email-verification'; import { isServerRunning, postToServer } from '../../3rdparty/email-verification';
const EMAIL_VERIFICATION = 7; // id in the `BadgeReg.sol` contract const EMAIL_VERIFICATION = 7; // id in the `BadgeReg.sol` contract
@ -59,6 +59,10 @@ export default class EmailVerificationStore extends VerificationStore {
super(api, EmailVerificationABI, EMAIL_VERIFICATION, account, isTestnet); super(api, EmailVerificationABI, EMAIL_VERIFICATION, account, isTestnet);
} }
isServerRunning = () => {
return isServerRunning(this.isTestnet);
}
requestValues = () => [ sha3.text(this.email) ] requestValues = () => [ sha3.text(this.email) ]
@action setEmail = (email) => { @action setEmail = (email) => {

View File

@ -21,7 +21,7 @@ import SMSVerificationABI from '~/contracts/abi/sms-verification.json';
import VerificationStore, { import VerificationStore, {
LOADING, QUERY_DATA, QUERY_CODE, POSTED_CONFIRMATION, DONE LOADING, QUERY_DATA, QUERY_CODE, POSTED_CONFIRMATION, DONE
} from './store'; } from './store';
import { postToServer } from '../../3rdparty/sms-verification'; import { isServerRunning, postToServer } from '../../3rdparty/sms-verification';
const SMS_VERIFICATION = 0; // id in the `BadgeReg.sol` contract const SMS_VERIFICATION = 0; // id in the `BadgeReg.sol` contract
@ -58,6 +58,10 @@ export default class SMSVerificationStore extends VerificationStore {
super(api, SMSVerificationABI, SMS_VERIFICATION, account, isTestnet); super(api, SMSVerificationABI, SMS_VERIFICATION, account, isTestnet);
} }
isServerRunning = () => {
return isServerRunning(this.isTestnet);
}
@action setNumber = (number) => { @action setNumber = (number) => {
this.number = number; this.number = number;
} }

View File

@ -40,6 +40,7 @@ export default class VerificationStore {
@observable fee = null; @observable fee = null;
@observable isVerified = null; @observable isVerified = null;
@observable hasRequested = null; @observable hasRequested = null;
@observable isServerRunning = null;
@observable consentGiven = false; @observable consentGiven = false;
@observable requestTx = null; @observable requestTx = null;
@observable code = ''; @observable code = '';
@ -73,6 +74,14 @@ export default class VerificationStore {
const { contract, account } = this; const { contract, account } = this;
this.step = LOADING; this.step = LOADING;
const isServerRunning = this.isServerRunning()
.then((isRunning) => {
this.isServerRunning = isRunning;
})
.catch((err) => {
this.error = 'Failed to check if server is running: ' + err.message;
});
const fee = contract.instance.fee.call() const fee = contract.instance.fee.call()
.then((fee) => { .then((fee) => {
this.fee = fee; this.fee = fee;
@ -101,7 +110,7 @@ export default class VerificationStore {
}); });
Promise Promise
.all([ fee, isVerified, hasRequested ]) .all([ isServerRunning, fee, isVerified, hasRequested ])
.then(() => { .then(() => {
this.step = QUERY_DATA; this.step = QUERY_DATA;
}); });

View File

@ -94,10 +94,10 @@ class Verification extends Component {
return ( return (
<Modal <Modal
actions={ this.renderDialogActions(phase, error, isStepValid) } actions={ this.renderDialogActions(phase, error, isStepValid) }
title='verify your account'
visible
current={ phase } current={ phase }
steps={ ['Method', 'Enter Data', 'Request', 'Enter Code', 'Confirm', 'Done!'] } steps={ ['Method', 'Enter Data', 'Request', 'Enter Code', 'Confirm', 'Done!'] }
title='verify your account'
visible
waiting={ error ? [] : [ 2, 4 ] } waiting={ error ? [] : [ 2, 4 ] }
> >
{ this.renderStep(phase, error) } { this.renderStep(phase, error) }
@ -111,8 +111,9 @@ class Verification extends Component {
const cancel = ( const cancel = (
<Button <Button
key='cancel' label='Cancel'
icon={ <CancelIcon /> } icon={ <CancelIcon /> }
key='cancel'
label='Cancel'
onClick={ onClose } onClick={ onClose }
/> />
); );
@ -125,9 +126,10 @@ class Verification extends Component {
<div> <div>
{ cancel } { cancel }
<Button <Button
key='done' label='Done'
disabled={ !isStepValid } disabled={ !isStepValid }
icon={ <DoneIcon /> } icon={ <DoneIcon /> }
key='done'
label='Done'
onClick={ onClose } onClick={ onClose }
/> />
</div> </div>
@ -160,9 +162,15 @@ class Verification extends Component {
<div> <div>
{ cancel } { cancel }
<Button <Button
key='next' label='Next'
disabled={ !isStepValid } disabled={ !isStepValid }
icon={ <IdentityIcon address={ account } button /> } icon={
<IdentityIcon
address={ account }
button
/>
}
key='next'
label='Next'
onClick={ action } onClick={ action }
/> />
</div> </div>
@ -180,16 +188,16 @@ class Verification extends Component {
const value = values.findIndex((v) => v.value === method); const value = values.findIndex((v) => v.value === method);
return ( return (
<RadioButtons <RadioButtons
onChange={ this.selectMethod }
value={ value < 0 ? 0 : value } value={ value < 0 ? 0 : value }
values={ values } values={ values }
onChange={ this.selectMethod }
/> />
); );
} }
const { const {
step, step,
fee, isVerified, hasRequested, isServerRunning, fee, isVerified, hasRequested,
requestTx, isCodeValid, confirmationTx, requestTx, isCodeValid, confirmationTx,
setCode setCode
} = this.store; } = this.store;
@ -223,15 +231,21 @@ class Verification extends Component {
return ( return (
<GatherData <GatherData
fee={ fee }
hasRequested={ hasRequested }
isServerRunning={ isServerRunning }
isVerified={ isVerified }
method={ method } fields={ fields } method={ method } fields={ fields }
fee={ fee } isVerified={ isVerified } hasRequested={ hasRequested }
setConsentGiven={ setConsentGiven } setConsentGiven={ setConsentGiven }
/> />
); );
case 2: case 2:
return ( return (
<SendRequest step={ step } tx={ requestTx } /> <SendRequest
step={ step }
tx={ requestTx }
/>
); );
case 3: case 3:
@ -245,16 +259,19 @@ class Verification extends Component {
} }
return ( return (
<QueryCode <QueryCode
receiver={ receiver }
hint={ hint } hint={ hint }
isCodeValid={ isCodeValid } isCodeValid={ isCodeValid }
receiver={ receiver }
setCode={ setCode } setCode={ setCode }
/> />
); );
case 4: case 4:
return ( return (
<SendConfirmation step={ step } tx={ confirmationTx } /> <SendConfirmation
step={ step }
tx={ confirmationTx }
/>
); );
case 5: case 5: