From 29d0e5c4d5a3764ceacf7f6d76c33878d90d560b Mon Sep 17 00:00:00 2001 From: wenzhe Date: Sun, 29 Sep 2019 14:41:33 +0800 Subject: [PATCH 1/4] checkin recaptcha --- package.json | 1 + src/components/DailyCheckin/action.js | 6 +- src/components/DailyCheckin/index.js | 32 +++++++++- src/constants.js | 2 + src/index.js | 4 ++ src/pages/SignIn/index.js | 90 ++++++++++++++++++++++++--- yarn.lock | 18 +++++- 7 files changed, 142 insertions(+), 11 deletions(-) diff --git a/package.json b/package.json index ffa32f14..15bc1b4f 100755 --- a/package.json +++ b/package.json @@ -72,6 +72,7 @@ "qrcode": "^1.3.3", "react": "^16.8.6", "react-dom": "^16.8.6", + "react-google-recaptcha": "^2.0.1", "react-intl": "^2.8.0", "react-onclickoutside": "^6.8.0", "react-redux": "^7.0.2", diff --git a/src/components/DailyCheckin/action.js b/src/components/DailyCheckin/action.js index ed690c6d..c1c21234 100644 --- a/src/components/DailyCheckin/action.js +++ b/src/components/DailyCheckin/action.js @@ -42,8 +42,10 @@ export const getCheckInInfo = () => dispatch => { }); }; -export const submitCheckIn = () => dispatch => { - reqSubmitCheckIn().then(body => { +export const submitCheckIn = recaptchaVal => dispatch => { + reqSubmitCheckIn({ + recaptchaVal, + }).then(body => { const param = { checkinStatus: body.result.status, checkinRemainingTime: body.result.remainingTime, diff --git a/src/components/DailyCheckin/index.js b/src/components/DailyCheckin/index.js index 8b7faacb..80d7e9f0 100644 --- a/src/components/DailyCheckin/index.js +++ b/src/components/DailyCheckin/index.js @@ -4,9 +4,12 @@ import moment from 'moment'; import styled from 'styled-components'; import { withRouter } from 'react-router-dom'; import { connect } from 'react-redux'; +import ReCAPTCHA from 'react-google-recaptcha'; import * as actions from './action'; import { compose, commonPropTypes, i18nTxt, auth } from '../../utils'; import CheckIn from '../../assets/iconfont/checkIn.svg'; +import Modal from '../Modal'; +import { recaptchaKey } from '../../constants'; const DailyCheckinWrap = styled.div` .pos-rightbottom { @@ -124,6 +127,13 @@ const svgOrange = ( /* eslint jsx-a11y/alt-text: 0 */ class DailyCheckin extends Component { + constructor(...args) { + super(...args); + this.state = { + showRecaptcha: false, + }; + } + componentDidMount() { const { history, common, getCheckInInfo } = this.props; @@ -142,13 +152,16 @@ class DailyCheckin extends Component { render() { const { common, submitCheckIn, showAlreadyTips } = this.props; const { checkinStatus, checkinFansCoin } = common; + const { showRecaptcha } = this.state; let checkInButton; if (checkinStatus === actions.checkinEnum.pass) { checkInButton = (
{ - submitCheckIn(); + this.setState({ + showRecaptcha: true, + }); }} className="btn-checkin pos-rightbottom" > @@ -195,10 +208,27 @@ class DailyCheckin extends Component {
); + const recaptchaModal = ( + +
+ { + submitCheckIn(val); + this.setState({ + showRecaptcha: false, + }); + }} + /> +
+
+ ); + return ( {checkInButton} {successPanel} + {recaptchaModal} ); } diff --git a/src/constants.js b/src/constants.js index 6393838d..718a382f 100644 --- a/src/constants.js +++ b/src/constants.js @@ -41,3 +41,5 @@ export const { SOLUTION_STATUS_ENUM } = bountyEnum; export const { MILESTONE_STATUS_ENUM } = bountyEnum; export const { REWARD_STATUS_ENUM } = bountyEnum; export const { WITHDRAWAL_STATUS_ENUM } = bountyEnum; + +export const recaptchaKey = '6LcGDroUAAAAAIDuTI9RpZNIuCi-QpSEKCdq_I4i'; diff --git a/src/index.js b/src/index.js index 43af3a48..c6deb6cf 100644 --- a/src/index.js +++ b/src/index.js @@ -9,6 +9,10 @@ import rootReducer from './reducers/index'; import App from './App'; import { updateDispatch } from './utils'; +window.recaptchaOptions = { + useRecaptchaNet: true, +}; + Sentry.init({ dsn: 'https://14d772ae785b46d2979814725a251882@sentry.conflux-chain.org/3' }); if (!global.Intl) { diff --git a/src/pages/SignIn/index.js b/src/pages/SignIn/index.js index 3d211c22..634a68e7 100644 --- a/src/pages/SignIn/index.js +++ b/src/pages/SignIn/index.js @@ -8,12 +8,31 @@ import styled from 'styled-components'; import { connect } from 'react-redux'; import { Link } from 'react-router-dom'; import PropTypes from 'prop-types'; +import ReCAPTCHA from 'react-google-recaptcha'; import { StyledWrapper } from '../../globalStyles/common'; import Input from '../../components/Input'; import { sendRequest, auth, i18nTxt } from '../../utils'; import { notice } from '../../components/Message/notice'; import { getAccount } from '../../components/PageHead/action'; import SignInVia from '../../components/SignInVia'; +import { recaptchaKey } from '../../constants'; + +export const getRecaptchaErr = (errCodes = []) => { + const reContains = a => { + return errCodes.indexOf(a) !== -1; + }; + let noticeMsg = ''; + if (reContains('missing-input-secret') || reContains('invalid-input-secret')) { + noticeMsg = i18nTxt('invalid recaptcha secret'); + } else if (reContains('missing-input-response') || reContains('invalid-input-response')) { + noticeMsg = i18nTxt('invalid recaptcha secret'); + } else if (reContains('timeout-or-duplicate')) { + noticeMsg = i18nTxt('recaptcha check timeout, please reload page'); + } else if (reContains('bad-request')) { + noticeMsg = i18nTxt('invalid recaptcha request'); + } + return noticeMsg; +}; class SignIn extends Component { constructor(...args) { @@ -28,7 +47,9 @@ class SignIn extends Component { inputsValue: { email, password: '', + recaptchaVal: '', }, + showHalfExtend: false, }; } @@ -58,7 +79,7 @@ class SignIn extends Component { onSigninClick = async () => { const { - inputsValue: { email, password }, + inputsValue: { email, password, recaptchaVal }, rememberUsernameChecked, } = this.state; @@ -66,16 +87,24 @@ class SignIn extends Component { body: { code, result }, } = await sendRequest({ url: '/user/login', - body: { email, password }, + body: { email, password, recaptchaVal }, manualNotice: true, }); if (code !== 0) { - notice.show({ - content: i18nTxt('Login failed. Check your username or password.'), - type: 'message-error', - timeout: 3000, - }); + if (result.recaptcha.success !== true) { + notice.show({ + content: getRecaptchaErr(result.recaptcha['error-codes']), + type: 'message-error', + timeout: 3000, + }); + } else { + notice.show({ + content: i18nTxt('Login failed. Check your username or password.'), + type: 'message-error', + timeout: 3000, + }); + } return; } @@ -93,6 +122,7 @@ class SignIn extends Component { const { rememberUsernameChecked, inputsValue: { email, password }, + showHalfExtend, } = this.state; return ( @@ -125,6 +155,23 @@ class SignIn extends Component { } }} /> + + { + const { inputsValue } = this.state; + this.setState({ inputsValue: { ...inputsValue, recaptchaVal: val } }); + }} + asyncScriptOnLoad={() => { + setTimeout(() => { + this.setState({ + showHalfExtend: true, + }); + }, 400); + }} + /> + +