diff options
Diffstat (limited to 'cmd/web')
-rw-r--r-- | cmd/web/Makefile | 2 | ||||
-rw-r--r-- | cmd/web/js/api.js | 21 | ||||
-rw-r--r-- | cmd/web/js/change_password.jsx | 62 | ||||
-rw-r--r-- | cmd/web/js/main.jsx | 34 | ||||
-rw-r--r-- | cmd/web/js/password_reset.jsx | 57 | ||||
-rw-r--r-- | cmd/web/package.json | 1 | ||||
-rw-r--r-- | cmd/web/yarn.lock | 4 |
7 files changed, 180 insertions, 1 deletions
diff --git a/cmd/web/Makefile b/cmd/web/Makefile index c6bc2bd..c5d5d62 100644 --- a/cmd/web/Makefile +++ b/cmd/web/Makefile | |||
@@ -4,7 +4,7 @@ export PATH := $(PATH):./node_modules/.bin | |||
4 | 4 | ||
5 | SRC_DIR=js | 5 | SRC_DIR=js |
6 | BUILD_DIR=build/js | 6 | BUILD_DIR=build/js |
7 | JSX_SRC= main.jsx signup.jsx signin.jsx otp.jsx poloniex.jsx | 7 | JSX_SRC= main.jsx signup.jsx signin.jsx otp.jsx poloniex.jsx password_reset.jsx change_password.jsx |
8 | JS_SRC= cookies.js app.js api.js | 8 | JS_SRC= cookies.js app.js api.js |
9 | STATIC_FILES= index.html style.css | 9 | STATIC_FILES= index.html style.css |
10 | JSX_OBJS=$(addprefix $(BUILD_DIR)/,$(JSX_SRC:.jsx=.js)) | 10 | JSX_OBJS=$(addprefix $(BUILD_DIR)/,$(JSX_SRC:.jsx=.js)) |
diff --git a/cmd/web/js/api.js b/cmd/web/js/api.js index 5cbf5eb..c9b4ef5 100644 --- a/cmd/web/js/api.js +++ b/cmd/web/js/api.js | |||
@@ -43,6 +43,27 @@ var ApiEndpoints = { | |||
43 | return '/signin'; | 43 | return '/signin'; |
44 | } | 44 | } |
45 | }, | 45 | }, |
46 | 'RESET_PASSWORD': { | ||
47 | 'type': 'POST', | ||
48 | 'auth': false, | ||
49 | 'parameters': [ | ||
50 | {'name': 'email', 'mandatory': true, 'inquery': true}, | ||
51 | ], | ||
52 | 'buildUrl': function() { | ||
53 | return '/passwordreset'; | ||
54 | } | ||
55 | }, | ||
56 | 'CHANGE_PASSWORD': { | ||
57 | 'type': 'POST', | ||
58 | 'auth': false, | ||
59 | 'parameters': [ | ||
60 | {'name': 'token', 'mandatory': true, 'inquery': true}, | ||
61 | {'name': 'password', 'mandatory': true, 'inquery': true}, | ||
62 | ], | ||
63 | 'buildUrl': function() { | ||
64 | return '/changepassword'; | ||
65 | } | ||
66 | }, | ||
46 | 'MARKET': { | 67 | 'MARKET': { |
47 | 'type': 'GET', | 68 | 'type': 'GET', |
48 | 'auth': true, | 69 | 'auth': true, |
diff --git a/cmd/web/js/change_password.jsx b/cmd/web/js/change_password.jsx new file mode 100644 index 0000000..aedf4af --- /dev/null +++ b/cmd/web/js/change_password.jsx | |||
@@ -0,0 +1,62 @@ | |||
1 | import Api from './api.js'; | ||
2 | import App from './app.js'; | ||
3 | import classNames from 'classnames'; | ||
4 | import React from 'react'; | ||
5 | |||
6 | class ChangePasswordForm extends React.Component { | ||
7 | constructor(props) { | ||
8 | super(props); | ||
9 | this.state = {'hideMsg': true, 'msg': '', 'msgOk': false, 'password': ''}; | ||
10 | } | ||
11 | |||
12 | handleSubmit = (e) => { | ||
13 | Api.Call( | ||
14 | 'CHANGE_PASSWORD', | ||
15 | { | ||
16 | 'password': this.state.password, | ||
17 | 'token': this.props.token | ||
18 | }, | ||
19 | function(err, status, data) { | ||
20 | if (err) { | ||
21 | console.error(err, data); | ||
22 | this.displayMessage(App.errorCodeToMessage(err.code), false); | ||
23 | return; | ||
24 | } | ||
25 | |||
26 | this.displayMessage('You password has been reset.', true); | ||
27 | this.props.onSuccess(); | ||
28 | |||
29 | }.bind(this) | ||
30 | ); | ||
31 | e.preventDefault(); | ||
32 | } | ||
33 | |||
34 | handlePasswordChange = (event) => { | ||
35 | this.setState({'password': event.target.value}); | ||
36 | } | ||
37 | |||
38 | hideMessage = () => { | ||
39 | this.setState({'hideMsg': true}); | ||
40 | } | ||
41 | |||
42 | displayMessage = (msg, ok) => { | ||
43 | this.setState({'msg': msg, 'msgOk': ok, 'hideMsg': false}); | ||
44 | } | ||
45 | |||
46 | render = () => { | ||
47 | var cName = classNames('form-message', {'hidden': this.state.hideMsg, 'message-ok': this.state.msgOk}); | ||
48 | return ( | ||
49 | <div className="row sign-in"> | ||
50 | <div className="offset-4 col-4 col-xs-offset-1 col-xs-10 text-center"> | ||
51 | <form role="form" onSubmit={this.handleSubmit}> | ||
52 | <input className="form-control" type="password" placeholder="password" onChange={this.handlePasswordChange} /> | ||
53 | <input className="form-control submit" type="submit" value="Change password" /> | ||
54 | <div className={cName}>{this.state.msg}</div> | ||
55 | </form> | ||
56 | </div> | ||
57 | </div> | ||
58 | ); | ||
59 | } | ||
60 | } | ||
61 | |||
62 | export default ChangePasswordForm; | ||
diff --git a/cmd/web/js/main.jsx b/cmd/web/js/main.jsx index e64adc7..909f1bd 100644 --- a/cmd/web/js/main.jsx +++ b/cmd/web/js/main.jsx | |||
@@ -1,11 +1,14 @@ | |||
1 | import SignupForm from './signup.js'; | 1 | import SignupForm from './signup.js'; |
2 | import SigninForm from './signin.js'; | 2 | import SigninForm from './signin.js'; |
3 | import PasswordResetForm from './password_reset.js'; | ||
4 | import ChangePasswordForm from './change_password.js'; | ||
3 | import OtpEnrollForm from './otp.js'; | 5 | import OtpEnrollForm from './otp.js'; |
4 | import PoloniexController from './poloniex.js'; | 6 | import PoloniexController from './poloniex.js'; |
5 | import App from './app.js'; | 7 | import App from './app.js'; |
6 | import Api from './api.js'; | 8 | import Api from './api.js'; |
7 | import cookies from './cookies.js'; | 9 | import cookies from './cookies.js'; |
8 | import React from 'react'; | 10 | import React from 'react'; |
11 | import qs from 'qs'; | ||
9 | 12 | ||
10 | class Header extends React.Component { | 13 | class Header extends React.Component { |
11 | render = () => { | 14 | render = () => { |
@@ -60,6 +63,37 @@ App.page('/signin', false, function(context) { | |||
60 | </div>); | 63 | </div>); |
61 | }); | 64 | }); |
62 | 65 | ||
66 | App.page('/reset-password', false, function(context) { | ||
67 | if (App.isUserSignedIn()) { | ||
68 | App.go('/me'); | ||
69 | return; | ||
70 | } | ||
71 | |||
72 | App.mount(<div> | ||
73 | <Header /> | ||
74 | <PasswordResetForm /> | ||
75 | </div>); | ||
76 | }); | ||
77 | |||
78 | App.page('/change-password', false, function(context) { | ||
79 | if (App.isUserSignedIn()) { | ||
80 | App.go('/me'); | ||
81 | return; | ||
82 | } | ||
83 | |||
84 | var token = qs.parse(context.querystring).token; | ||
85 | |||
86 | if (token === undefined) { | ||
87 | App.go('/'); | ||
88 | return; | ||
89 | } | ||
90 | |||
91 | App.mount(<div> | ||
92 | <Header /> | ||
93 | <ChangePasswordForm token={token} onSuccess={App.go.bind(App, '/signin')}/> | ||
94 | </div>); | ||
95 | }); | ||
96 | |||
63 | App.page('/signout', true, function(context) { | 97 | App.page('/signout', true, function(context) { |
64 | cookies.removeItem('jwt'); | 98 | cookies.removeItem('jwt'); |
65 | 99 | ||
diff --git a/cmd/web/js/password_reset.jsx b/cmd/web/js/password_reset.jsx new file mode 100644 index 0000000..8cbdc60 --- /dev/null +++ b/cmd/web/js/password_reset.jsx | |||
@@ -0,0 +1,57 @@ | |||
1 | import Api from './api.js'; | ||
2 | import App from './app.js'; | ||
3 | import classNames from 'classnames'; | ||
4 | import React from 'react'; | ||
5 | |||
6 | class PasswordResetForm extends React.Component { | ||
7 | constructor(props) { | ||
8 | super(props); | ||
9 | this.state = {'hideMsg': true, 'msg': '', 'msgOk': false, 'email': ''}; | ||
10 | } | ||
11 | |||
12 | handleSubmit = (e) => { | ||
13 | Api.Call('RESET_PASSWORD', {'email': this.state.email}, function(err, status, data) { | ||
14 | if (err) { | ||
15 | console.error(err, data); | ||
16 | this.displayMessage(App.errorCodeToMessage(err.code), false); | ||
17 | return; | ||
18 | } | ||
19 | |||
20 | this.displayMessage('You will receive a reset link to reset your password.', true); | ||
21 | if (this.props.onSuccess) { | ||
22 | this.props.onSuccess(); | ||
23 | } | ||
24 | |||
25 | }.bind(this)); | ||
26 | e.preventDefault(); | ||
27 | } | ||
28 | |||
29 | handleEmailChange = (event) => { | ||
30 | this.setState({'email': event.target.value}); | ||
31 | } | ||
32 | |||
33 | hideMessage = () => { | ||
34 | this.setState({'hideMsg': true}); | ||
35 | } | ||
36 | |||
37 | displayMessage = (msg, ok) => { | ||
38 | this.setState({'msg': msg, 'msgOk': ok, 'hideMsg': false}); | ||
39 | } | ||
40 | |||
41 | render = () => { | ||
42 | var cName = classNames('form-message', {'hidden': this.state.hideMsg, 'message-ok': this.state.msgOk}); | ||
43 | return ( | ||
44 | <div className="row sign-in"> | ||
45 | <div className="offset-4 col-4 col-xs-offset-1 col-xs-10 text-center"> | ||
46 | <form role="form" onSubmit={this.handleSubmit}> | ||
47 | <input className="form-control" type="email" placeholder="email" onChange={this.handleEmailChange} /> | ||
48 | <input className="form-control submit" type="submit" value="Reset" /> | ||
49 | <div className={cName}>{this.state.msg}</div> | ||
50 | </form> | ||
51 | </div> | ||
52 | </div> | ||
53 | ); | ||
54 | } | ||
55 | } | ||
56 | |||
57 | export default PasswordResetForm; \ No newline at end of file | ||
diff --git a/cmd/web/package.json b/cmd/web/package.json index c9241f1..a867313 100644 --- a/cmd/web/package.json +++ b/cmd/web/package.json | |||
@@ -14,6 +14,7 @@ | |||
14 | "localenvify": "^1.0.1", | 14 | "localenvify": "^1.0.1", |
15 | "page": "^1.8.3", | 15 | "page": "^1.8.3", |
16 | "path-to-regexp": "^1.2.1", | 16 | "path-to-regexp": "^1.2.1", |
17 | "qs": "^6.5.1", | ||
17 | "react": "^16.2.0" | 18 | "react": "^16.2.0" |
18 | }, | 19 | }, |
19 | "devDependencies": { | 20 | "devDependencies": { |
diff --git a/cmd/web/yarn.lock b/cmd/web/yarn.lock index 0d162a9..b2218ee 100644 --- a/cmd/web/yarn.lock +++ b/cmd/web/yarn.lock | |||
@@ -3536,6 +3536,10 @@ q@~1.0.0, q@~1.0.1: | |||
3536 | version "1.0.1" | 3536 | version "1.0.1" |
3537 | resolved "https://registry.yarnpkg.com/q/-/q-1.0.1.tgz#11872aeedee89268110b10a718448ffb10112a14" | 3537 | resolved "https://registry.yarnpkg.com/q/-/q-1.0.1.tgz#11872aeedee89268110b10a718448ffb10112a14" |
3538 | 3538 | ||
3539 | qs@^6.5.1: | ||
3540 | version "6.5.1" | ||
3541 | resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.1.tgz#349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8" | ||
3542 | |||
3539 | qs@~1.2.0: | 3543 | qs@~1.2.0: |
3540 | version "1.2.2" | 3544 | version "1.2.2" |
3541 | resolved "https://registry.yarnpkg.com/qs/-/qs-1.2.2.tgz#19b57ff24dc2a99ce1f8bdf6afcda59f8ef61f88" | 3545 | resolved "https://registry.yarnpkg.com/qs/-/qs-1.2.2.tgz#19b57ff24dc2a99ce1f8bdf6afcda59f8ef61f88" |