|
1 |
/* |
|
|
2 |
* Copyright 2015-2016 Univention GmbH |
3 |
* |
4 |
* http://www.univention.de/ |
5 |
* |
6 |
* All rights reserved. |
7 |
* |
8 |
* The source code of this program is made available |
9 |
* under the terms of the GNU Affero General Public License version 3 |
10 |
* (GNU AGPL V3) as published by the Free Software Foundation. |
11 |
* |
12 |
* Binary versions of this program provided by Univention to you as |
13 |
* well as other copyrighted, protected or trademarked materials like |
14 |
* Logos, graphics, fonts, specific documentations and configurations, |
15 |
* cryptographic keys etc. are subject to a license agreement between |
16 |
* you and Univention and not subject to the GNU AGPL V3. |
17 |
* |
18 |
* In the case you use this program under the terms of the GNU AGPL V3, |
19 |
* the program is provided in the hope that it will be useful, |
20 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
21 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
22 |
* GNU Affero General Public License for more details. |
23 |
* |
24 |
* You should have received a copy of the GNU Affero General Public |
25 |
* License with the Debian GNU/Linux or Univention distribution in file |
26 |
* /usr/share/common-licenses/AGPL-3; if not, see |
27 |
* <http://www.gnu.org/licenses/>. |
28 |
*/ |
29 |
/*global define require console window */ |
30 |
|
31 |
define([ |
32 |
"dojo/_base/lang", |
33 |
"dojo/_base/array", |
34 |
"dojo/on", |
35 |
"dojo/keys", |
36 |
"dojo/dom", |
37 |
"dojo/json", |
38 |
"dojo/request/xhr", |
39 |
"dijit/form/Button", |
40 |
"put-selector/put", |
41 |
"./ContainerWidget", |
42 |
"./LabelPane", |
43 |
"./TextBox", |
44 |
"./RadioButton", |
45 |
"./lib", |
46 |
"./i18n!." |
47 |
], function(lang, array, on, keys, dom, json, xhr, Button, put, ContainerWidget, LabelPane, TextBox, RadioButton, lib, _) { |
48 |
|
49 |
return { |
50 |
selectedTokenMethod: null, |
51 |
|
52 |
_createTitle: function() { |
53 |
var title = _('Password Reset'); |
54 |
var siteDescription = _('On this page you can reset your lost password or provide contact information for setting a new password in the future.'); |
55 |
document.title = title; |
56 |
var titleNode = dom.byId('title'); |
57 |
put(titleNode, 'h1', title); |
58 |
put(titleNode, 'p', siteDescription); |
59 |
put(titleNode, '!.dijitHidden'); |
60 |
}, |
61 |
|
62 |
_createContent: function() { |
63 |
var contentNode = dom.byId('content'); |
64 |
var formNode = this._getFormNode(); |
65 |
put(formNode, '[id=form].step!dijitHidden'); |
66 |
put(contentNode, formNode); |
67 |
this._fillContentByUrl(); |
68 |
}, |
69 |
|
70 |
_getFormNode: function() { |
71 |
var formNode = put('div[style="overflow: hidden;"]'); |
72 |
|
73 |
// step 1 username and link to contact information |
74 |
this.usernameNode = put(formNode, 'div.step'); |
75 |
put(this.usernameNode, 'p > b', _('Reset your password.')); |
76 |
put(this.usernameNode, 'p', _('Please provide your username to receive a token that is required to reset your password.')); |
77 |
var stepContent = put(this.usernameNode, 'div.stepContent'); |
78 |
this._username = new TextBox({ |
79 |
label: _('Username'), |
80 |
'class': 'soloLabelPane', |
81 |
isValid: function() { |
82 |
return !!this.get('value'); |
83 |
}, |
84 |
required: true |
85 |
}); |
86 |
this._username.on('keyup', lang.hitch(this, function(evt) { |
87 |
if (evt.keyCode === keys.ENTER) { |
88 |
this._getResetMethods(); |
89 |
} |
90 |
})); |
91 |
put(stepContent, this._username.label.domNode); |
92 |
this._username.startup(); |
93 |
this._usernameButton = new Button({ |
94 |
label: _('Next'), |
95 |
onClick: lang.hitch(this, '_getResetMethods') |
96 |
}); |
97 |
put(stepContent, this._usernameButton.domNode); |
98 |
|
99 |
// contact information |
100 |
this.contactNode = put(formNode, 'div.step'); |
101 |
put(this.contactNode, 'p > b', _('Provide your contact information.')); |
102 |
put(this.contactNode, 'p', { |
103 |
innerHTML: lang.replace(_('Please click the following link to <a href="/univention-self-service/{0}#setcontactinformation">change your contact information</a> for resetting your password in the future.', [lib.getCurrentLanguageQuery()])) |
104 |
}); |
105 |
|
106 |
// step 2 token |
107 |
this.tokenNode = put(formNode, 'div.step.hide-step'); |
108 |
var skipStep = function() { |
109 |
put(this.newPasswordNode, '!hide-step'); |
110 |
put(this._requestTokenButton.domNode, '.dijitHidden'); |
111 |
this._requestTokenButton.set('disabled', true); |
112 |
}; |
113 |
var descRequestToken = put(this.tokenNode, 'p', _('Please choose a method to receive the token.')); |
114 |
put(descRequestToken, 'span', { |
115 |
innerHTML: _(' If you already have a token you can <a>skip this step</a>.'), |
116 |
onclick: lang.hitch(this, skipStep) |
117 |
}); |
118 |
stepContent = put(this.tokenNode, 'div.stepContent'); |
119 |
this._tokenOptions = new ContainerWidget({}); |
120 |
put(stepContent, this._tokenOptions.domNode); |
121 |
this._requestTokenButton = new Button({ |
122 |
label: _('Next'), |
123 |
onClick: lang.hitch(this, '_requestToken') |
124 |
}); |
125 |
put(stepContent, this._requestTokenButton.domNode); |
126 |
|
127 |
// step 3 use the token to set a new password |
128 |
this.newPasswordNode = put(formNode, 'div.step.hide-step'); |
129 |
var prevStep = function() { |
130 |
put(this.newPasswordNode, '.hide-step'); |
131 |
put(this.tokenNode, '!dijitHidden'); |
132 |
put(this.tokenNode, '!hide-step'); |
133 |
put(this._requestTokenButton.domNode, '!dijitHidden'); |
134 |
this._requestTokenButton.set('disabled', false); |
135 |
}; |
136 |
var descNewPassword = put(this.newPasswordNode, 'p', _('Please enter the token and your new password.')); |
137 |
put(descNewPassword, 'span', { |
138 |
innerHTML: _(' If your token has expired you can <a>request a new token</a>.'), |
139 |
onclick: lang.hitch(this, prevStep) |
140 |
}); |
141 |
stepContent = put(this.newPasswordNode, 'div.stepContent'); |
142 |
this._token = new TextBox({ |
143 |
label: _('Token'), |
144 |
'class': 'soloLabelPane', |
145 |
isValid: function() { |
146 |
return !!this.get('value'); |
147 |
}, |
148 |
required: true |
149 |
}); |
150 |
this._token.on('keyup', lang.hitch(this, function(evt) { |
151 |
if (evt.keyCode === keys.ENTER) { |
152 |
this._setPassword(); |
153 |
} |
154 |
})); |
155 |
put(stepContent, this._token.label.domNode); |
156 |
this._token.startup(); |
157 |
|
158 |
this._newPassword = new TextBox({ |
159 |
label: _('New password'), |
160 |
type: 'password', |
161 |
'class': 'doubleLabelPane left', |
162 |
isValid: function() { |
163 |
return !!this.get('value'); |
164 |
}, |
165 |
required: true |
166 |
}); |
167 |
this._newPassword.on('keyup', lang.hitch(this, function(evt) { |
168 |
if (evt.keyCode === keys.ENTER) { |
169 |
this._setPassword(); |
170 |
} |
171 |
})); |
172 |
put(stepContent, this._newPassword.label.domNode); |
173 |
this._newPassword.startup(); |
174 |
|
175 |
this._verifyPassword = new TextBox({ |
176 |
label: _('New password (retype)'), |
177 |
type: 'password', |
178 |
'class': 'doubleLabelPane', |
179 |
isValid: lang.hitch(this, function() { |
180 |
return this._newPassword.get('value') === |
181 |
this._verifyPassword.get('value'); |
182 |
}), |
183 |
invalidMessage: _('The passwords do not match, please retype again.'), |
184 |
required: true |
185 |
}); |
186 |
this._verifyPassword.on('keyup', lang.hitch(this, function(evt) { |
187 |
if (evt.keyCode === keys.ENTER) { |
188 |
this._setPassword(); |
189 |
} |
190 |
})); |
191 |
put(stepContent, this._verifyPassword.label.domNode); |
192 |
this._verifyPassword.startup(); |
193 |
this._setPasswordButton = new Button({ |
194 |
label: _('Change password'), |
195 |
onClick: lang.hitch(this, '_setPassword') |
196 |
}); |
197 |
put(stepContent, this._setPasswordButton.domNode); |
198 |
return formNode; |
199 |
}, |
200 |
|
201 |
_getResetMethods: function() { |
202 |
this._username.set('disabled', true); |
203 |
this._usernameButton.set('disabled', true); |
204 |
|
205 |
if (this._username.isValid()) { |
206 |
data = json.stringify({ |
207 |
'username': this._username.get('value') |
208 |
}); |
209 |
xhr.post('passwordreset/get_reset_methods', { |
210 |
handleAs: 'json', |
211 |
headers: { |
212 |
'Content-Type': 'application/json', |
213 |
'Accept-Language': lib.getQuery('lang') || 'en-US' |
214 |
}, |
215 |
data: data |
216 |
}).then(lang.hitch(this, function(data) { |
217 |
lib._removeMessage(); |
218 |
put(this._usernameButton.domNode, '.dijitHidden'); |
219 |
put(this.contactNode, '!'); |
220 |
this._buildTokenOptions(data.result); |
221 |
}), lang.hitch(this, function(err){ |
222 |
var message = err.name + ": " + err.message; |
223 |
if (err.response && err.response.data && err.response.data.message) { |
224 |
message = err.response.data.message; |
225 |
} |
226 |
lib.showMessage({ |
227 |
content: message, |
228 |
targetNode: this.usernameNode, |
229 |
'class': '.error' |
230 |
}); |
231 |
this._usernameButton.set('disabled', false); |
232 |
this._username.set('disabled', false); |
233 |
})); |
234 |
} else { |
235 |
this._usernameButton.set('disabled', false); |
236 |
this._username.set('disabled', false); |
237 |
} |
238 |
}, |
239 |
|
240 |
_buildTokenOptions: function(options) { |
241 |
array.forEach(options, lang.hitch(this, function(obj, idx){ |
242 |
var radioButton = new RadioButton({ |
243 |
name: 'button' + idx, |
244 |
label: obj.label, |
245 |
method: obj.id, |
246 |
checked: idx === 0, |
247 |
radioButtonGroup: 'token', |
248 |
_categoryID: 'token' |
249 |
}); |
250 |
var label = new LabelPane({ |
251 |
'class': 'ucsRadioButtonLabel', |
252 |
content: radioButton |
253 |
}); |
254 |
this._tokenOptions.addChild(label); |
255 |
})); |
256 |
put(this.tokenNode, '!hide-step'); |
257 |
}, |
258 |
|
259 |
_requestToken: function() { |
260 |
// get selected method for requesting a token |
261 |
array.some(this._tokenOptions.getChildren(), lang.hitch(this, function(tokenLabel) { |
262 |
var radioButton = tokenLabel.getChildren()[0]; |
263 |
if (radioButton.checked) { |
264 |
this.selectedTokenMethod = { |
265 |
label: radioButton.get('label'), |
266 |
method: radioButton.get('method') |
267 |
}; |
268 |
} |
269 |
})); |
270 |
|
271 |
if (this.selectedTokenMethod) { |
272 |
this._requestTokenButton.set('disabled', true); |
273 |
data = json.stringify({ |
274 |
'username': this._username.get('value'), |
275 |
'method': this.selectedTokenMethod.method |
276 |
}); |
277 |
xhr.post('passwordreset/send_token', { |
278 |
handleAs: 'json', |
279 |
headers: { |
280 |
'Content-Type': 'application/json', |
281 |
'Accept-Language': lib.getQuery('lang') || 'en-US' |
282 |
}, |
283 |
data: data |
284 |
}).then(lang.hitch(this, function(data) { |
285 |
lib.showMessage({ |
286 |
content: data.message, |
287 |
targetNode: this.tokenNode, |
288 |
'class': '.success' |
289 |
}); |
290 |
put(this._requestTokenButton.domNode, '.dijitHidden'); |
291 |
put(this.newPasswordNode, '!hide-step'); |
292 |
}), lang.hitch(this, function(err){ |
293 |
var message = err.name + ": " + err.message; |
294 |
if (err.response && err.response.data && err.response.data.message) { |
295 |
message = err.response.data.message; |
296 |
} |
297 |
lib.showMessage({ |
298 |
content: message, |
299 |
targetNode: this.tokenNode, |
300 |
'class': '.error' |
301 |
}); |
302 |
this._requestTokenButton.set('disabled', false); |
303 |
})); |
304 |
} |
305 |
}, |
306 |
|
307 |
_setPassword: function() { |
308 |
this._setPasswordButton.set('disabled', true); |
309 |
this._token.set('disabled', true); |
310 |
this._newPassword.set('disabled', true); |
311 |
this._verifyPassword.set('disabled', true); |
312 |
|
313 |
var isTokenAndNewPassValid = this._token.isValid() && |
314 |
this._newPassword.isValid() && |
315 |
this._verifyPassword.isValid(); |
316 |
|
317 |
if (isTokenAndNewPassValid) { |
318 |
data = json.stringify({ |
319 |
'username': this._username.get('value'), |
320 |
'password': this._verifyPassword.get('value'), |
321 |
'token' : this._token.get('value') |
322 |
}); |
323 |
xhr.post('passwordreset/set_password', { |
324 |
handleAs: 'json', |
325 |
headers: { |
326 |
'Content-Type': 'application/json', |
327 |
'Accept-Language': lib.getQuery('lang') || 'en-US' |
328 |
}, |
329 |
data: data |
330 |
}).then(lang.hitch(this, function(data) { |
331 |
lib._removeMessage(); |
332 |
var callback = function() { |
333 |
lib.showLastMessage({ |
334 |
content: data.message, |
335 |
'class': '.success' |
336 |
}); |
337 |
}; |
338 |
lib.wipeOutNode({ |
339 |
node: dom.byId('form'), |
340 |
callback: callback |
341 |
}); |
342 |
}), lang.hitch(this, function(err){ |
343 |
var message = err.name + ": " + err.message; |
344 |
if (err.response && err.response.data && err.response.data.message) { |
345 |
message = err.response.data.message; |
346 |
} |
347 |
lib.showMessage({ |
348 |
content: message, |
349 |
targetNode: this.newPasswordNode, |
350 |
'class': '.error' |
351 |
}); |
352 |
this._setPasswordButton.set('disabled', false); |
353 |
this._token.set('disabled', false); |
354 |
this._newPassword.set('disabled', false); |
355 |
this._verifyPassword.set('disabled', false); |
356 |
})); |
357 |
} else { |
358 |
this._setPasswordButton.set('disabled', false); |
359 |
this._token.set('disabled', false); |
360 |
this._newPassword.set('disabled', false); |
361 |
this._verifyPassword.set('disabled', false); |
362 |
} |
363 |
}, |
364 |
|
365 |
_fillContentByUrl: function() { |
366 |
// checks if the url contains a username and a token |
367 |
// show and fill the corresponding input fields if true |
368 |
var token = lib.getQuery('token'); |
369 |
var username = lib.getQuery('username'); |
370 |
if (token && username) { |
371 |
this._username.set('value', username); |
372 |
this._token.set('value', token); |
373 |
put(this.contactNode, '!'); |
374 |
this._getResetMethods(); |
375 |
this._requestTokenButton.set('disabled', true); |
376 |
put(this.tokenNode, '.dijitHidden'); |
377 |
put(this.newPasswordNode, '!hide-step'); |
378 |
} |
379 |
}, |
380 |
|
381 |
start: function() { |
382 |
this._createTitle(); |
383 |
this._createContent(); |
384 |
} |
385 |
}; |
386 |
}); |