commit ed3522b4fc555672d3489f4d10e79def3fa4cf13 Author: Florian Best Date: Tue Sep 6 16:13:40 2016 +0200 Changes from Alex Kramer diff --git a/management/univention-self-service/34univention-self-service.inst b/management/univention-self-service/34univention-self-service.inst old mode 100755 new mode 100644 diff --git a/management/univention-self-service/35univention-self-service-passwordreset-umc.inst b/management/univention-self-service/35univention-self-service-passwordreset-umc.inst old mode 100755 new mode 100644 diff --git a/management/univention-self-service/65univention-self-service-passwordreset-umc.uinst b/management/univention-self-service/65univention-self-service-passwordreset-umc.uinst old mode 100755 new mode 100644 diff --git a/management/univention-self-service/66univention-self-service.uinst b/management/univention-self-service/66univention-self-service.uinst old mode 100755 new mode 100644 diff --git a/management/univention-self-service/build_profile.js b/management/univention-self-service/build_profile.js index 061d245..e243655 100644 --- a/management/univention-self-service/build_profile.js +++ b/management/univention-self-service/build_profile.js @@ -58,11 +58,12 @@ var profile = { layers: { "dojo/dojo": { - customBase: true, - include: [ - "ucs/passwordchange", - "ucs/passwordreset" - ] + customBase: true //, + //include: [ + // "ucs/PasswordChange", + // "ucs/PasswordForgotten", + // "ucs/ProtectAccountAccess" + //] } } }; diff --git a/management/univention-self-service/conffiles/usr/share/univention-self-service/www/entries.json b/management/univention-self-service/conffiles/usr/share/univention-self-service/www/entries.json new file mode 100644 index 0000000..0f0b7f8 --- /dev/null +++ b/management/univention-self-service/conffiles/usr/share/univention-self-service/www/entries.json @@ -0,0 +1,33 @@ +@!@ +import json + +subpages = ['password_change', 'password_forgotten', 'protect_account_access'] +subpage_variable_path = "umc/self-service/passwordservice/subpage/{}" +filtered_subpages = [page for page in subpages if configRegistry.is_true(subpage_variable_path.format(page))] + + +password_qualities = [ + 'credit/digits', + 'credit/lower', + 'credit/upper', + 'credit/other', + 'forbidden/chars', + 'required/chars' +] +quality_variable_path = "password/quality/{}" +filtered_password_qualities = [] +for quality in password_qualities: + ucr_variable = quality_variable_path.format(quality) + value = configRegistry.get(ucr_variable); + if value: + filtered_password_qualities.append({ + 'name': quality, + 'value': value + }) + + +print json.dumps({ + "subpages": filtered_subpages, + "password_quality": filtered_password_qualities +}) +@!@ diff --git a/management/univention-self-service/css/document.styl b/management/univention-self-service/css/document.styl index 0252069..30a5fa5 100644 --- a/management/univention-self-service/css/document.styl +++ b/management/univention-self-service/css/document.styl @@ -133,6 +133,69 @@ div#title > p { color: #619410; } +div.PasswordServiceContent { + background: #f3f3f3; + padding: 1.3em; + border-radius: 5px 5px 5px 5px; + -moz-border-radius: 5px 5px 5px 5px; + -webkit-border-radius: 5px 5px 5px 5px; + border: 0px solid #000000; + -webkit-box-shadow: 6px 6px 5px 0px rgba(131,131,131,1); + -moz-box-shadow: 6px 6px 5px 0px rgba(131,131,131,1); + box-shadow: 6px 6px 5px 0px rgba(131,131,131,1); + + .contentDesc { + font-weight: bold; + } +} + +ol.PasswordOl { + margin-left: 0; + padding-right: 0; + padding-left: 0; + list-style-type: none; + + li.step { + counter-increment: step-counter; + margin-bottom: 1em; + + div { + margin-top: 0.1em; + } + + .dijitButton { + margin: 0.6em 0.6em 0 0; + } + } + + li.step::before { + content: counter(step-counter); + margin-right: 5px; + font-size: 80%; + background-color: rgb(200,200,200); + color: white; + font-weight: bold; + padding: 3px 8px; + border-radius: 3px; + } + + div.stepLabel { + display: inline; + } +} + +ol#PasswordChangeSteps li.step::before { + background-color: #8ebe43; +} + +ol#PasswordForgottenSteps li.step::before { + background-color: #fd5745; +} + +ol#PasswordProtectSteps li.step::before { + background-color: #f8cd23; +} + div.stepContent { margin-top: 1.5em; } @@ -151,6 +214,7 @@ div.step { div.step.hide-step { opacity: 0; + display: none; visibility: hidden; transition: visibility 0s linear 0.5s, opacity 0.5s ease-in-out; } diff --git a/management/univention-self-service/css/form/Common.styl b/management/univention-self-service/css/form/Common.styl index 094c1e6..44f0562 100644 --- a/management/univention-self-service/css/form/Common.styl +++ b/management/univention-self-service/css/form/Common.styl @@ -192,7 +192,7 @@ .claro .dijitSelectDisabled, .claro .dijitTextBoxDisabled, .claro .dijitTextBoxDisabled .dijitInputInner { - color: $disabled-text-color; + //color: $disabled-text-color; } .dj_webkit .claro .dijitDisabled input { diff --git a/management/univention-self-service/css/header.styl b/management/univention-self-service/css/header.styl index 50a3119..6fa74d5 100644 --- a/management/univention-self-service/css/header.styl +++ b/management/univention-self-service/css/header.styl @@ -7,6 +7,22 @@ } +#header-middle { + position: absolute; + left: 50%; + top: 13px; + width: 20px; + height: 20px; + margin-left: -10px; + background: url("../../univention-management-console/js/dijit/themes/umc/images/icons.svg") -40px -20px no-repeat; +} + +#header-middle:hover { + background: url("../../univention-management-console/js/dijit/themes/umc/images/icons.svg") -60px -20px no-repeat; +} + + + #header-left { //float:left; left: 0; diff --git a/management/univention-self-service/css/tabs.styl b/management/univention-self-service/css/tabs.styl index 2044f59..78b049f 100644 --- a/management/univention-self-service/css/tabs.styl +++ b/management/univention-self-service/css/tabs.styl @@ -4,50 +4,50 @@ } #navigation { - .button-container { + .PasswordServiceNav { display: inline-block; + width: 14.2857%; + min-width: 95px; + max-width: 160px; + margin: 5px 0; + position: relative; + vertical-align: top; + cursor: pointer; } - .button { + .PasswordServiceNav:active { + font-weight: bold; + } + + .PasswordServiceNavBubble { + -webkit-border-radius: 50%; + -moz-border-radius: 50%; + border-radius: 50%; + background-color: aliceblue; width: 70px; height: 70px; - margin: 0 2em; - background: url(icons/tab-buttons.svg) no-repeat; - display: inline-block; + margin: auto; + background-repeat: no-repeat; + background-position: 50% 40%; } - - #register-button { - background-position: 0 -70px; - &.focused { - background-position: 0 0; + .password_change { + background-color: #8ebe43; + background-image: url("../../icon/password_change.png"); } - } - - #upload-button { - background-position: -70px -70px; - &.focused { - background-position: -70px 0; + .password_forgotten { + background-color: #fd5745; + background-image: url("../../icon/password_forgotten.png"); } - } - - #finished-button { - background-position: -140px -70px; - &.focused { - background-position: -140px 0; + .protect_account_access { + background-color: #f8cd23; + background-image: url("../../icon/protect_account_access.png"); } - } - - .loading-bar { - opacity: 0; - transition: opacity 1s ease-in-out; - width: 100%; - height: 32px; - background: url(icons/loading-bubbles.gif) no-repeat; - background-position: center center; - } - .loading-bar.focused { - opacity: 1; + .PasswordServiceNavTitle { + display: block; + font-size: 1em; + margin-top: 0.5em; + white-space: pre-line; } } diff --git a/management/univention-self-service/debian/rules b/management/univention-self-service/debian/rules old mode 100755 new mode 100644 diff --git a/management/univention-self-service/debian/univention-self-service.install b/management/univention-self-service/debian/univention-self-service.install index 8ca922b..75e6707 100644 --- a/management/univention-self-service/debian/univention-self-service.install +++ b/management/univention-self-service/debian/univention-self-service.install @@ -5,3 +5,4 @@ univention-self-service-modules usr/sbin/ www usr/share/univention-self-service usr/share/univention-self-service/www/ var/www/univention-self-service +icon/*.png var/www/icon diff --git a/management/univention-self-service/debian/univention-self-service.postinst b/management/univention-self-service/debian/univention-self-service.postinst index e943477..71318eb 100644 --- a/management/univention-self-service/debian/univention-self-service.postinst +++ b/management/univention-self-service/debian/univention-self-service.postinst @@ -52,27 +52,26 @@ touch $ACCESS_LOG $ERROR_LOG chown self-service:adm $ACCESS_LOG $ERROR_LOG chmod 640 $ACCESS_LOG $ERROR_LOG -univention-config-registry set \ - self-service/passwordreset/web/enabled?yes \ - "ucs/web/overview/entries/service/passwordreset/description=Reset your password or provide contact information" \ - "ucs/web/overview/entries/service/passwordreset/description/de=Setzen Sie Ihr Passwort zurück oder hinterlegen Sie Kontaktinformationen." \ - "ucs/web/overview/entries/service/passwordreset/label=Password Reset" \ - "ucs/web/overview/entries/service/passwordreset/label/de=Passwort zurücksetzen" \ - "ucs/web/overview/entries/service/passwordreset/link=/univention-self-service/?lang=en-US#passwordreset" \ - "ucs/web/overview/entries/service/passwordreset/link/de=/univention-self-service/?lang=de-DE#passwordreset" \ - "ucs/web/overview/entries/service/passwordreset/port_http=" \ - "ucs/web/overview/entries/service/passwordreset/port_https=443" +# UCR Variable für Passwort Service +# default: Passwort Service aktiviert +univention-config-registry set self-service/passwordchange/web/enabled?yes -univention-config-registry set \ - self-service/passwordchange/web/enabled?yes \ - "ucs/web/overview/entries/service/passwordchange/description=Change your (expired) password." \ - "ucs/web/overview/entries/service/passwordchange/description/de=Ändern Sie Ihr (abgelaufenes) Passwort." \ - "ucs/web/overview/entries/service/passwordchange/label=Change Password" \ - "ucs/web/overview/entries/service/passwordchange/label/de=Passwort ändern" \ - "ucs/web/overview/entries/service/passwordchange/link=/univention-self-service/?lang=en-US#passwordchange" \ - "ucs/web/overview/entries/service/passwordchange/link/de=/univention-self-service/?lang=de-DE#passwordchange" \ +# UCR Variablen für Unterseiten des Passwort Services +univention-config-registry set "umc/self-service/passwordservice/subpage/password_change=yes" \ + "umc/self-service/passwordservice/subpage/password_forgotten=yes" \ + "umc/self-service/passwordservice/subpage/protect_account_access=yes" + +# Link für Passwort Service +# Informationen für den Link zum Passwort Service +univention-config-registry set "ucs/web/overview/entries/service/passwordchange/label=Password settings" \ + "ucs/web/overview/entries/service/passwordchange/label/de=Passwort-Einstellungen" \ + "ucs/web/overview/entries/service/passwordchange/description=Password change and protection." \ + "ucs/web/overview/entries/service/passwordchange/description/de=Passwort ändern und Kontozugang schützen." \ + "ucs/web/overview/entries/service/passwordchange/link=/univention-self-service/?lang=en-US" \ + "ucs/web/overview/entries/service/passwordchange/link/de=/univention-self-service/?lang=de-DE" \ "ucs/web/overview/entries/service/passwordchange/port_http=" \ - "ucs/web/overview/entries/service/passwordchange/port_https=443" + "ucs/web/overview/entries/service/passwordchange/port_https=443" \ + "ucs/web/overview/entries/service/passwordchange/icon=/icon/password.png" if [ "$1" = "configure" ]; then diff --git a/management/univention-self-service/debian/univention-self-service.postrm b/management/univention-self-service/debian/univention-self-service.postrm index 65c890e..50524a5 100644 --- a/management/univention-self-service/debian/univention-self-service.postrm +++ b/management/univention-self-service/debian/univention-self-service.postrm @@ -38,18 +38,9 @@ case "$1" in ;; esac +# UCR Variablen bei Deinstallation löschen if [ "$1" = "remove" -o "$1" = "purge" ]; then - univention-config-registry unset \ - ucs/web/overview/entries/service/passwordreset/description \ - ucs/web/overview/entries/service/passwordreset/description/de \ - ucs/web/overview/entries/service/passwordreset/icon \ - ucs/web/overview/entries/service/passwordreset/label \ - ucs/web/overview/entries/service/passwordreset/label/de \ - ucs/web/overview/entries/service/passwordreset/link \ - ucs/web/overview/entries/service/passwordreset/link/de \ - ucs/web/overview/entries/service/passwordreset/port_http \ - ucs/web/overview/entries/service/passwordreset/port_https - + # Informationen für den Link zum Passwort Service löschen univention-config-registry unset \ ucs/web/overview/entries/service/passwordchange/description \ ucs/web/overview/entries/service/passwordchange/description/de \ @@ -59,7 +50,14 @@ if [ "$1" = "remove" -o "$1" = "purge" ]; then ucs/web/overview/entries/service/passwordchange/link \ ucs/web/overview/entries/service/passwordchange/link/de \ ucs/web/overview/entries/service/passwordchange/port_http \ - ucs/web/overview/entries/service/passwordchange/port_https + ucs/web/overview/entries/service/passwordchange/port_https \ + ucs/web/overview/entries/service/passwordchange/icon + + # UCR Variablen für die Unterseiten des Passwort Services löschen + univention-config-registry unset \ + umc/self-service/passwordservice/subpage/password_change \ + umc/self-service/passwordservice/subpage/password_forgotten \ + umc/self-service/passwordservice/subpage/protect_account_access # restart, so apache unloads WSGI and deactivats plugin in its config # retry if fail because of to quick successive restarts (from other frontend packages) diff --git a/management/univention-self-service/debian/univention-self-service.univention-config-registry b/management/univention-self-service/debian/univention-self-service.univention-config-registry index 072dbe0..1362a90 100644 --- a/management/univention-self-service/debian/univention-self-service.univention-config-registry +++ b/management/univention-self-service/debian/univention-self-service.univention-config-registry @@ -2,3 +2,8 @@ Type: file File: usr/share/univention-self-service/www/languages.json Variables: locale Variables: ucs/server/languages/.* + +Type: file +File: usr/share/univention-self-service/www/entries.json +Variables: umc/self-service/passwordservice/subpage/.* +Variables: password/quality/.* diff --git a/management/univention-self-service/debian/univention-self-service.univention-config-registry-variables b/management/univention-self-service/debian/univention-self-service.univention-config-registry-variables index dd7ca94..4570af3 100644 --- a/management/univention-self-service/debian/univention-self-service.univention-config-registry-variables +++ b/management/univention-self-service/debian/univention-self-service.univention-config-registry-variables @@ -15,3 +15,21 @@ Description[de]=Die Webseite des Password-Self-Service Moduls einschalten (Stand Description[en]=Enable the web page of the password self service module (default "yes"). Type=bool Categories=self-service + +[umc/self-service/passwordservice/subpage/password_change] +Description[de]=Die Unterseite "Passwort ändern" des Password-Self-Service Moduls einschalten (Standard: "yes"). +Description[en]=Enable the sub page "Password change" of the password self service module (default "yes"). +Type=bool +Categories=self-service + +[umc/self-service/passwordservice/subpage/password_forgotten] +Description[de]=Die Unterseite "Passwort vergessen" des Password-Self-Service Moduls einschalten (Standard: "yes"). +Description[en]=Enable the sub page "Password forgotten" of the password self service module (default "yes"). +Type=bool +Categories=self-service + +[umc/self-service/passwordservice/subpage/protect_account_access] +Description[de]=Die Unterseite "Kontozugäng schützen" des Password-Self-Service Moduls einschalten (Standard: "yes"). +Description[en]=Enable the sub page "Protect account access" of the password self service module (default "yes"). +Type=bool +Categories=self-service diff --git a/management/univention-self-service/icon/password.png b/management/univention-self-service/icon/password.png new file mode 100644 index 0000000..9c7ea5f Binary files /dev/null and b/management/univention-self-service/icon/password.png differ diff --git a/management/univention-self-service/icon/password_change.png b/management/univention-self-service/icon/password_change.png new file mode 100644 index 0000000..86aa6e2 Binary files /dev/null and b/management/univention-self-service/icon/password_change.png differ diff --git a/management/univention-self-service/icon/password_forgotten.png b/management/univention-self-service/icon/password_forgotten.png new file mode 100644 index 0000000..dafb497 Binary files /dev/null and b/management/univention-self-service/icon/password_forgotten.png differ diff --git a/management/univention-self-service/icon/protect_account_access.png b/management/univention-self-service/icon/protect_account_access.png new file mode 100644 index 0000000..5a32e0e Binary files /dev/null and b/management/univention-self-service/icon/protect_account_access.png differ diff --git a/management/univention-self-service/js/config.js b/management/univention-self-service/js/config.js index aa263b2..fc28e3d 100644 --- a/management/univention-self-service/js/config.js +++ b/management/univention-self-service/js/config.js @@ -1,43 +1,43 @@ -// get locale from query string -function getQuery(/*String*/ param, /*mixed*/ defaultVal) { - // parse the URI query string - var query = window.location.search.substring(1); - var vars = query.split('&'); - for (var i = 0; i < vars.length; i++) { - // parse the tuple - var tuple = vars[i].split('='); - // check whether we found the particular parameter we are interested in - if (2 == tuple.length && param == tuple[0]) { +/** +* Search the value of the QueryString for an given key. +* @param: {string} key - Key for the searched value. +* @param: {mixed} defaultVal - default value if no value is found. +* */ +function getQuery(key, defaultVal) { + var queryString = window.location.search.substring(1); + var items = queryString.split('&'); + for (var i = 0; i < items.length; i++) { + var tuple = items[i].split('='); + if (2 == tuple.length && key == tuple[0]) { return tuple[1]; } } + return defaultVal; } -locale = getQuery('lang'); -if (locale) { + +/** + * Get the current language from the queryString + * */ +function getLocale() { + var locale = getQuery('lang', 'en-US'); locale = locale.replace('_', '-'); + return locale; } -// load the javascript module that is specified in the hash -var selfService = document.location.hash.substr(1); var dojoConfig = { isDebug: false, - locale: locale, + locale: getLocale(), async: true, callback: function() { require([ - "dojo/hash", - "dojo/topic", - "ucs/" + selfService, + "ucs/PasswordService", "ucs/LanguagesDropDown", "dojo/domReady!" - ], function(hash, topic, app, LanguagesDropDown) { - app.start(); + ], function(PasswordService, LanguagesDropDown) { + PasswordService.start(); LanguagesDropDown.start(); - topic.subscribe("/dojo/hashchange", function(changedHash) { - window.location.reload(); - }); }); } }; diff --git a/management/univention-self-service/js/ucs/LabelPane.js b/management/univention-self-service/js/ucs/LabelPane.js index 1305802..9752458 100644 --- a/management/univention-self-service/js/ucs/LabelPane.js +++ b/management/univention-self-service/js/ucs/LabelPane.js @@ -270,7 +270,7 @@ define([ if (description && !this.content.handlesTooltips) { //default to the 'new' tooltip style if (!this.usesHoverTooltip) { - if (this._isLabelDisplayed() && this.label && !(this.label === ' ')) { + if (this._isLabelDisplayed() && this.label && this.label !== ' ') { labelNode = this._getLabelNode(); this.tooltipNode = domConstruct.create("div",{ 'class': "umcDescription umcDescriptionIcon" diff --git a/management/univention-self-service/js/ucs/PasswordBox.js b/management/univention-self-service/js/ucs/PasswordBox.js new file mode 100644 index 0000000..47fa920 --- /dev/null +++ b/management/univention-self-service/js/ucs/PasswordBox.js @@ -0,0 +1,161 @@ +/* + * Copyright 2011-2016 Univention GmbH + * + * http://www.univention.de/ + * + * All rights reserved. + * + * The source code of this program is made available + * under the terms of the GNU Affero General Public License version 3 + * (GNU AGPL V3) as published by the Free Software Foundation. + * + * Binary versions of this program provided by Univention to you as + * well as other copyrighted, protected or trademarked materials like + * Logos, graphics, fonts, specific documentations and configurations, + * cryptographic keys etc. are subject to a license agreement between + * you and Univention and not subject to the GNU AGPL V3. + * + * In the case you use this program under the terms of the GNU AGPL V3, + * the program is provided in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public + * License with the Debian GNU/Linux or Univention distribution in file + * /usr/share/common-licenses/AGPL-3; if not, see + * . + */ +/*global define*/ + +define([ + "dojo/_base/declare", + "dojo/_base/lang", + "dojo/_base/array", + "dojo/when", + "dojo/json", + "dijit/form/ValidationTextBox", + "./_FormWidgetMixin", + "./LabelPane", + "./lib", + "./i18n!." +], function(declare, lang, array, when, json, ValidationTextBox, _FormWidgetMixin, LabelPane, lib, _) { + return declare('umc.widgets.PasswordBox', [ ValidationTextBox, _FormWidgetMixin ], { + label: null, + type: 'password', + required: true, + missingMessage: _('This value is required.'), + promptMessage: '', + invalidMessage: '', + tooltipPosition: ['below', 'after'], + active_password_qualities: null, + password_qualities: { + 'credit/digits': { + reg: '.{%[0]}', + promptMessage: _('Required length:') + }, + 'credit/lower': { + reg: '^(.*?[a-z]){%[0],}', + promptMessage: _('Required number of lower case letters:') + }, + 'credit/upper': { + reg: '^(.*?[A-Z]){%[0],}', + promptMessage: _('Required number of upper case letters:') + }, + 'credit/other': { + reg: '^(.*?[^a-zA-Z0-9]){%[0],}', + promptMessage: _('Required number of special characters (nor digit or letters):') + }, + 'forbidden/chars': { + reg: "^((?![%[0]]).)*$", + promptMessage: _('Forbidden chars:') + }, + 'required/chars': { + reg: '[%[0]]', + promptMessage: _('Required chars:') + } + }, + + buildRendering: function() { + this.inherited(arguments); + if (this.label !== undefined) { + this._createLabelNode(); + } + when(lib.getBackendInformation()).then(lang.hitch(this, function(data) { + var result = JSON.parse(data, true); + this.active_password_qualities = result.password_quality; + this.setPromptMessage(result.password_quality); + })); + }, + + isValid: function() { + return this.validator(); + }, + + _hasValue: function(password) { + if (password) { + return true; + } else { + this.setPromptMessage(); + this.invalidMessage = _('This value is required.'); + return false; + } + }, + + /** Checks if the password meets the active password qualities. + * @param {string} password - Current value of the input box. + * **/ + _hasValidPasswordQuality: function(password) { + var result = array.filter(this.active_password_qualities, lang.hitch(this, function(iqual) { + var quality = this.password_qualities[iqual.name]; + var reg_str = lang.replace(quality.reg, [iqual.value], /\%\[([^\]]+)\]/g); + var reg = new RegExp(reg_str); + if (reg.test(password)) { + return true; + } else { + this.invalidMessage += lang.replace('{0} {1}{2}', [quality.promptMessage, iqual.value, '
']); + this.promptMessage = this.invalidMessage; + return false; + } + })); + if (result.length === this.active_password_qualities.length) { + this.setValid(true); + return true; + } else { + return false; + } + }, + + validator: function() { + this.invalidMessage = ''; + this.promptMessage = ''; + var password = this.get('value'); + return this._hasValue(password) && this._hasValidPasswordQuality(password); + }, + + setPromptMessage: function(active_qualities) { + var qualities = active_qualities || this.active_password_qualities; + if (qualities && qualities.length) { + this.promptMessage = _('The password must fullfill following conditions:'); + array.forEach(qualities, lang.hitch(this, function(iqual) { + var quality = this.password_qualities[iqual.name]; + this.promptMessage += lang.replace('{0}{1} {2}', ['
', quality.promptMessage, iqual.value]); + })); + } + }, + + _createLabelNode: function() { + this.label = new LabelPane({ + content: this, + 'class': this['class'] + }); + this.set('class', ''); + }, + + reset: function() { + this.set('value', ''); + this.set('disabled', false); + this.setValid(); + } + }); +}); diff --git a/management/univention-self-service/js/ucs/PasswordChange.js b/management/univention-self-service/js/ucs/PasswordChange.js new file mode 100644 index 0000000..e4507dc --- /dev/null +++ b/management/univention-self-service/js/ucs/PasswordChange.js @@ -0,0 +1,246 @@ +/* + * Copyright 2015-2016 Univention GmbH + * + * http://www.univention.de/ + * + * All rights reserved. + * + * The source code of this program is made available + * under the terms of the GNU Affero General Public License version 3 + * (GNU AGPL V3) as published by the Free Software Foundation. + * + * Binary versions of this program provided by Univention to you as + * well as other copyrighted, protected or trademarked materials like + * Logos, graphics, fonts, specific documentations and configurations, + * cryptographic keys etc. are subject to a license agreement between + * you and Univention and not subject to the GNU AGPL V3. + * + * In the case you use this program under the terms of the GNU AGPL V3, + * the program is provided in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public + * License with the Debian GNU/Linux or Univention distribution in file + * /usr/share/common-licenses/AGPL-3; if not, see + * . + */ +/*global define require console window */ + +define([ + "dojo/_base/lang", + "dojo/on", + "dojo/keys", + "dojo/dom", + "dojo/json", + "dojo/request/xhr", + "dijit/form/Button", + "put-selector/put", + "./TextBox", + "./PasswordBox", + "./lib", + "./i18n!." +], function(lang, on, keys, dom, json, xhr, Button, put, TextBox, PasswordBox, lib, _) { + + return { + title: _('Password change'), + desc: _('Change your (expired) password.'), + hash: 'passwordchange', + contentContainer: null, + steps: null, + + /** + * Returns the title of the subpage. + * */ + getTitle: function() { + return _(this.title); + }, + + /** + * Returns the description of the subpage. + * */ + getDesc: function() { + return _(this.desc); + }, + + /** + * Return the content node of the subpage. + * If the content does not exists, it will be generated. + * */ + getContent: function() { + if (!this.contentContainer) { + this.contentContainer = put('div.contentWrapper'); + put(this.contentContainer, 'div.contentDesc', this.getDesc()); + put(this.contentContainer, this._getSteps()); + } + return this.contentContainer; + }, + + /** + * Return the steps for the content node. + * If the steps do not exists, they will be generated. + * Note: Please call getContent for generating the steps. + * */ + _getSteps: function() { + if (!this.steps) { + this.steps = put('ol#PasswordChangeSteps.PasswordOl'); + this._createUsername(); + this._createOldPassword(); + this._createNewPassword(); + this._createSubmit(); + } + return this.steps; + }, + + /** + * Creates input field for username. + * */ + _createUsername: function() { + var step = put('li.step'); + var label = put('div.stepLabel', _('Username')); + put(step, label); + this._username = new TextBox({ + 'class': 'soloLabelPane', + isValid: function() { + return !!this.get('value'); + }, + required: true + }); + this._username.startup(); + put(step, this._username.domNode); + put(this.steps, step); + }, + + /** + * Creates input field for old password. + * */ + _createOldPassword: function() { + var step = put('li.step'); + var label = put('div.stepLabel', _('Old Password')); + put(step, label); + this._oldPassword = new TextBox({ + 'class': 'soloLabelPane', + type: 'password', + isValid: function() { + return !!this.get('value'); + }, + required: true + }); + this._oldPassword.startup(); + put(step, this._oldPassword.domNode); + put(this.steps, step); + }, + + /** + * Creates input fields for new password. + * */ + _createNewPassword: function() { + var step = put('li.step'); + var label = put('div.stepLabel', _('New Password')); + put(step, label); + this._newPassword = new PasswordBox({ + 'class': 'soloLabelPane left' + }); + this._newPassword.startup(); + put(step, this._newPassword.domNode); + put(this.steps, step); + + step = put('li.step'); + label = put('div.stepLabel', _('New Password (retype)')); + put(step, label); + this._verifyPassword = new TextBox({ + type: 'password', + 'class': 'soloLabelPane', + isValid: lang.hitch(this, function() { + return this._newPassword.get('value') === + this._verifyPassword.get('value'); + }), + invalidMessage: _('The passwords do not match, please retype again.'), + required: true + }); + this._verifyPassword.startup(); + put(step, this._verifyPassword.domNode); + put(this.steps, step); + }, + + /** + * Creates submit button. + * */ + _createSubmit: function() { + var step = put('div'); + this._submitButton = new Button({ + label: _('Change password'), + onClick: lang.hitch(this, '_setPassword') + }); + put(step, '>', this._submitButton.domNode); + + // let the user submit the form by pressing ENTER + on(document, "keyup", lang.hitch(this, function(evt) { + if (evt.keyCode === keys.ENTER && !this._submitButton.get('disabled')) { + this._setPassword(); + } + })); + put(this.steps, step); + }, + + /** + * Changes the current password if all input fields are valid. + * */ + _setPassword: function() { + this._submitButton.set('disabled', true); + var allInputFieldsAreValid = this._username.isValid() && + this._oldPassword.isValid() && + this._newPassword.isValid() && + this._verifyPassword.isValid(); + + if (allInputFieldsAreValid) { + data = json.stringify({ + password: { + 'username': this._username.get('value'), + 'password': this._oldPassword.get('value'), + 'new_password': this._newPassword.get('value') + } + }); + + xhr.post('/univention-management-console/set', { + handleAs: 'json', + headers: { + 'Content-Type': 'application/json', + 'Accept-Language': lib.getQuery('lang') || 'en-US' + }, + data: data + }).then(lang.hitch(this, function(data) { + lib.showLastMessage({ + content: data.message, + 'class': '.success' + }); + this._clearAllInputFields(); + }), lang.hitch(this, function(err) { + var message = err.name + ": " + err.message; + if (err.response && err.response.data && err.response.data.message) { + message = err.response.data.message; + } + lib.showMessage({ + content: message, + 'class': '.error' + }); + })).always(lang.hitch(this, function(){ + this._submitButton.set('disabled', false); + })); + } else { + this._submitButton.set('disabled', false); + } + }, + + /** + * Clears all input field values of the subpage. + * */ + _clearAllInputFields: function() { + this._username.reset(); + this._oldPassword.reset(); + this._newPassword.reset(); + this._verifyPassword.reset(); + } + }; +}); diff --git a/management/univention-self-service/js/ucs/PasswordForgotten.js b/management/univention-self-service/js/ucs/PasswordForgotten.js new file mode 100644 index 0000000..ed6c9f3 --- /dev/null +++ b/management/univention-self-service/js/ucs/PasswordForgotten.js @@ -0,0 +1,449 @@ +/* + * Copyright 2015-2016 Univention GmbH + * + * http://www.univention.de/ + * + * All rights reserved. + * + * The source code of this program is made available + * under the terms of the GNU Affero General Public License version 3 + * (GNU AGPL V3) as published by the Free Software Foundation. + * + * Binary versions of this program provided by Univention to you as + * well as other copyrighted, protected or trademarked materials like + * Logos, graphics, fonts, specific documentations and configurations, + * cryptographic keys etc. are subject to a license agreement between + * you and Univention and not subject to the GNU AGPL V3. + * + * In the case you use this program under the terms of the GNU AGPL V3, + * the program is provided in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public + * License with the Debian GNU/Linux or Univention distribution in file + * /usr/share/common-licenses/AGPL-3; if not, see + * . + */ +/*global define require console window */ + +define([ + "dojo/_base/lang", + "dojo/_base/array", + "dojo/on", + "dojo/keys", + "dojo/dom", + "dojo/json", + "dojo/request/xhr", + "dijit/form/Button", + "put-selector/put", + "./ContainerWidget", + "./LabelPane", + "./TextBox", + "./PasswordBox", + "./RadioButton", + "./lib", + "./i18n!." +], function(lang, array, on, keys, dom, json, xhr, Button, put, ContainerWidget, LabelPane, TextBox, PasswordBox, RadioButton, lib, _) { + + return { + title: _("Password forgotten"), + desc: _("Forgot your password? Set a new one: "), + altDesc: _("Set a new password!"), + hash: 'passwordreset', + contentContainer: null, + steps: null, + selectedRenewOption: null, + + /** + * Returns the title of the subpage. + * */ + getTitle: function() { + return _(this.title); + }, + + /** + * Returns the description for the subpage: + * Request New Password. + * */ + getRequestNewPassDesc: function() { + return _(this.desc); + }, + + /** + * Returns the description for the subpage: + * Set New Password. + * */ + getSetNewPassDesc: function() { + return _(this.altDesc); + }, + + /** + * Checks if the the query string contains credentials + * for setting a new password. + * True -Return a subpage to set a new password. + * False - Return a subpage to request a new password. + * */ + getContent: function() { + this.contentContainer = put('div.contentWrapper'); + var credentials = this._getCredentials(); + if (credentials) { + put(this.contentContainer, 'div.contentDesc', this.getSetNewPassDesc()); + put(this.contentContainer, this._getSetNewSteps()); + } else { + put(this.contentContainer, 'div.contentDesc', this.getRequestNewPassDesc()); + put(this.contentContainer, this._getRequestSteps()); + } + return this.contentContainer; + }, + + /** + * Return the steps for the subpage: + * Request New Password. + * If the steps do not exists, they will be generated. + * Note: Please call getContent for generating the steps. + * */ + _getRequestSteps: function() { + if (!this.steps) { + this.steps = put('ol#PasswordForgottenSteps.PasswordOl'); + this._createUsername(); + } + return this.steps; + }, + + /** + * Return the steps for the subpage: + * Set New Password. + * If the steps do not exists, they will be generated. + * Note: Please call getContent for generating the steps. + * */ + _getSetNewSteps: function() { + if (!this.steps) { + this.steps = put('ol#PasswordForgottenSteps.PasswordOl'); + this._createNewPassword(); + this._createSubmitNewPassword(); + } + return this.steps; + }, + + /** + * Creates input field for username and submit button. + * */ + _createUsername: function() { + var step = put('li.step'); + var label = put('div.stepLabel', _('Username')); + put(step, label); + this._username = new TextBox({ + 'class': 'soloLabelPane', + isValid: function() { + return !!this.get('value'); + }, + required: true + }); + this._username.on('keyup', lang.hitch(this, function(evt) { + if (evt.keyCode === keys.ENTER) { + this._getResetMethods(); + } + })); + this._username.startup(); + put(step, this._username.domNode); + + this._usernameButton = new Button({ + label: _('Next'), + onClick: lang.hitch(this, '_getResetMethods') + }); + put(step, this._usernameButton.domNode); + put(this.steps, step); + }, + + /** + * Gets the available renew options for the user from + * the server. + * */ + _getResetMethods: function() { + this._username.set('disabled', true); + this._usernameButton.set('disabled', true); + + if (this._username.isValid()) { + data = json.stringify({ + 'username': this._username.get('value') + }); + xhr.post('passwordreset/get_reset_methods', { + handleAs: 'json', + headers: { + 'Content-Type': 'application/json', + 'Accept-Language': lib.getQuery('lang') || 'en-US' + }, + data: data + }).then(lang.hitch(this, function(data) { + lib._removeMessage(); + put(this._usernameButton.domNode, '.dijitHidden'); + this._createRenewOptions(data.result); + }), lang.hitch(this, function(err){ + var message = err.name + ": " + err.message; + if (err.response && err.response.data && err.response.data.message) { + message = err.response.data.message; + } + lib.showMessage({ + content: message, + 'class': '.error' + }); + this._usernameButton.set('disabled', false); + this._username.set('disabled', false); + })); + } else { + this._usernameButton.set('disabled', false); + this._username.set('disabled', false); + } + }, + + /** + * Creates a list of all options which are + * available to request a new password. + * @param {array} options - List of password renew options. + * */ + _createRenewOptions: function(options) { + // TODO: skipable for having a pin + var step = put('li.step.hide-step'); + var label = put('div.stepLabel', _('Please choose an option to renew your password.')); + put(step, label); + var renewOptions = this._renderRenewOptions(options); + put(label, renewOptions); + this._requestTokenButton = new Button({ + label: _('Next'), + onClick: lang.hitch(this, '_requestToken') + }); + put(step, this._requestTokenButton.domNode); + put(this.steps, step); + }, + + /** + * Renders a pair of label and radioButton for each + * renew option. + * */ + _renderRenewOptions: function(options) { + this._tokenOptions = new ContainerWidget({}); + array.forEach(options, lang.hitch(this, function(obj, idx){ + var radioButton = new RadioButton({ + name: 'button' + idx, + label: obj.label, + method: obj.id, + checked: idx === 0, + radioButtonGroup: 'token', + _categoryID: 'token' + }); + var label = new LabelPane({ + 'class': 'ucsRadioButtonLabel', + content: radioButton + }); + this._tokenOptions.addChild(label); + })); + return this._tokenOptions.domNode; + }, + + /** + * Requests a mail or pin from the server to renew the + * password. + * */ + _requestToken: function() { + //TODO: Display the renew option for mobilenumber + //TODO: Add an option to request a new mail/sms + if (this._getRenewOption()) { + this._requestTokenButton.set('disabled', true); + data = json.stringify({ + 'username': this._username.get('value'), + 'method': this.selectedRenewOption.method + }); + xhr.post('passwordreset/send_token', { + handleAs: 'json', + headers: { + 'Content-Type': 'application/json', + 'Accept-Language': lib.getQuery('lang') || 'en-US' + }, + data: data + }).then(lang.hitch(this, function(data) { + this._showNewPasswordHowTo(); + lib.showMessage({ + content: data.message, + 'class': '.success' + }); + put(this._requestTokenButton.domNode, '.dijitHidden'); + }), lang.hitch(this, function(err){ + var message = err.name + ": " + err.message; + if (err.response && err.response.data && err.response.data.message) { + message = err.response.data.message; + } + lib.showMessage({ + content: message, + targetNode: this.tokenNode, + 'class': '.error' + }); + this._requestTokenButton.set('disabled', false); + })); + } + }, + + /** + * Gets the selected renew option. + * */ + _getRenewOption: function() { + array.some(this._tokenOptions.getChildren(), lang.hitch(this, function(option) { + var radioButton = option.getChildren()[0]; + if (radioButton.checked) { + this.selectedRenewOption= { + label: radioButton.get('label'), + method: radioButton.get('method') + }; + } + })); + return this.selectedRenewOption; + }, + + /** + * Creates a message with instructions about what + * todo next to renew the password. + * */ + _showNewPasswordHowTo: function() { + // TODO: add option for sms + var step = put('li.step'); + var label = put('div.stepLabel', _('You have mail!')); + put(step, label); + var msg = put('div.soloLabelPane', _('We have send you an e-mail to your alternative e-mail address, that you have provided on the page "Protect Account Access". Please check your mails and follow the link to renew your password.')); + put(step, msg); + var hint = put('div.soloLabelPane', _('If you did not received an e-mail please check your spam directory or use this link to go back to step 2.')); + put(step, hint); + put(this.steps, step); + }, + + /** + * Creates input fields to set a new password. + */ + _createNewPassword: function() { + var step = put('li.step'); + var label = put('div.stepLabel', _('New Password')); + put(step, label); + this._newPassword = new PasswordBox({ + 'class': 'soloLabelPane' + }); + this._newPassword.on('keyup', lang.hitch(this, function(evt) { + if (evt.keyCode === keys.ENTER) { + this._setPassword(); + } + })); + this._newPassword.startup(); + put(step, this._newPassword.domNode); + put(this.steps, step); + + step = put('li.step'); + label = put('div.stepLabel', _('New Password (retype)')); + put(step, label); + this._verifyPassword = new TextBox({ + type: 'password', + 'class': 'soloLabelPane', + isValid: lang.hitch(this, function() { + return this._newPassword.get('value') === + this._verifyPassword.get('value'); + }), + invalidMessage: _('The passwords do not match, please retype again.'), + required: true + }); + this._verifyPassword.on('keyup', lang.hitch(this, function(evt) { + if (evt.keyCode === keys.ENTER) { + this._setPassword(); + } + })); + this._verifyPassword.startup(); + put(step, this._verifyPassword.domNode); + put(this.steps, step); + }, + + /** + * Creates submit button. + * */ + _createSubmitNewPassword: function() { + var step = put('div'); + this._setPasswordButton = new Button({ + label: _('Change password'), + onClick: lang.hitch(this, '_setPassword') + }); + put(step, this._setPasswordButton.domNode); + put(this.steps, step); + }, + + /** + * Sets the new password by sending it to the server. + */ + _setPassword: function() { + this._disableNewPasswordInputs(true); + var credentials = this._getCredentials(); + + var isTokenAndNewPassValid = credentials && + this._newPassword.isValid() && + this._verifyPassword.isValid(); + + if (isTokenAndNewPassValid) { + data = json.stringify({ + 'username': credentials.username, + 'password': this._verifyPassword.get('value'), + 'token' : credentials.token + }); + xhr.post('passwordreset/set_password', { + handleAs: 'json', + headers: { + 'Content-Type': 'application/json', + 'Accept-Language': lib.getQuery('lang') || 'en-US' + }, + data: data + }).then(lang.hitch(this, function(data) { + lib.showLastMessage({ + content: data.message, + 'class': '.success' + }); + this._resetNewPasswordInputs(); + }), lang.hitch(this, function(err){ + var message = err.name + ": " + err.message; + if (err.response && err.response.data && err.response.data.message) { + message = err.response.data.message; + } + lib.showMessage({ + content: message, + targetNode: this.newPasswordNode, + 'class': '.error' + }); + this._disableNewPasswordInputs(false); + })); + } else { + this._disableNewPasswordInputs(false); + } + }, + + _disableNewPasswordInputs: function(/* boolean */ isDiabled) { + this._setPasswordButton.set('disabled', isDiabled); + this._newPassword.set('disabled', isDiabled); + this._verifyPassword.set('disabled', isDiabled); + }, + + _resetNewPasswordInputs: function() { + this._setPasswordButton.set('value', ''); + this._newPassword.set('value', ''); + this._verifyPassword.set('value', ''); + this._disableNewPasswordInputs(false); + }, + + /** + * Gets credentials (token and username) from query string. + * */ + _getCredentials: function() { + var token = lib.getQuery('token'); + var username = lib.getQuery('username'); + if (token && username) { + return { + username: username, + token: token + }; + } + return null; + } + }; +}); diff --git a/management/univention-self-service/js/ucs/PasswordService.js b/management/univention-self-service/js/ucs/PasswordService.js new file mode 100644 index 0000000..d7dbecd --- /dev/null +++ b/management/univention-self-service/js/ucs/PasswordService.js @@ -0,0 +1,143 @@ +/* + * Copyright 2015-2016 Univention GmbH + * + * http://www.univention.de/ + * + * All rights reserved. + * + * The source code of this program is made available + * under the terms of the GNU Affero General Public License version 3 + * (GNU AGPL V3) as published by the Free Software Foundation. + * + * Binary versions of this program provided by Univention to you as + * well as other copyrighted, protected or trademarked materials like + * Logos, graphics, fonts, specific documentations and configurations, + * cryptographic keys etc. are subject to a license agreement between + * you and Univention and not subject to the GNU AGPL V3. + * + * In the case you use this program under the terms of the GNU AGPL V3, + * the program is provided in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public + * License with the Debian GNU/Linux or Univention distribution in file + * /usr/share/common-licenses/AGPL-3; if not, see + * . + */ + +define([ + "dojo/hash", + "dojo/topic", + "dojo/_base/lang", + "dojo/_base/array", + "dojo/_base/xhr", + "dojo/json", + "put-selector/put", + "dojo/dom", + "dijit/layout/StackContainer", + "dijit/layout/ContentPane", + "./PasswordChange", + "./PasswordForgotten", + "./ProtectAccountAccess", + "./lib", + "dojo/domReady!" +], function(hash, topic, lang, array, xhr, JSON, put, dom, StackContainer, ContentPane, PasswordChange, PasswordForgotten, ProtectAccountAccess, lib){ + + return { + content_container: null, + content_controller: null, + backend_info: null, + subpages: { + "password_change": PasswordChange, + "password_forgotten": PasswordForgotten, + "protect_account_access": ProtectAccountAccess + }, + site_hashes: {}, + + /** + * Builds the active subpages of the + * Password Service. + */ + start: function() { + this._initContainer(); + this._initController(); + this._subscribeOnHashEvents(); + this._requestActiveSubpages(); + }, + + _subscribeOnHashEvents: function() { + topic.subscribe("/dojo/hashchange", lang.hitch(this, function(changedHash) { + //window.location.reload(); + lib._removeMessage(); + this._loadSubpage(changedHash); + })); + }, + + /** + * Requests the active subpages. + **/ + _requestActiveSubpages: function() { + xhr.get({ + url: "/univention-self-service/entries.json", + load: lang.hitch(this, function(data) { + this.backend_info = JSON.parse(data, true); + this._addSubPages(this.backend_info.subpages || []); + }), + error: lang.hitch(this, function(data) { + console.error(data); + }) + }); + }, + + _initContainer : function() { + this.content_container = new StackContainer({ + "class" : "PasswordServiceContent", + id: "contentContainer", + doLayout: false + }, "content"); + this.content_container.startup(); + }, + + _initController: function() { + var navContainer = dom.byId('navigation'); + this.content_controller = put(navContainer, ".PasswordServiceController"); + }, + + /** + * Adds the subpages by name to the Password Service. + * */ + _addSubPages: function(page_list) { + array.forEach(page_list, lang.hitch(this, function(page_name){ + var module = this.subpages[page_name]; + if (module) { + var subpage = new ContentPane({ + content: module.getContent() + }); + this.site_hashes[module.hash] = subpage; + var nav = put("div.PasswordServiceNav", { + onclick: lang.hitch(this, function() { + hash(module.hash); + }) + }); + var bubble = put(nav, "div.PasswordServiceNavBubble" + "." + page_name); + var title = put(nav, "div.PasswordServiceNavTitle", { + innerHTML: module.getTitle() + }); + put(this.content_controller, nav); + this.content_container.addChild(subpage); + } + })); + this._loadSubpage(hash()); + }, + + _loadSubpage: function(changedHash) { + var subpage = this.site_hashes[changedHash]; + if (!subpage) { + subpage = this.content_container.getChildren()[0]; + } + this.content_container.selectChild(subpage); + } + }; +}); diff --git a/management/univention-self-service/js/ucs/ProtectAccountAccess.js b/management/univention-self-service/js/ucs/ProtectAccountAccess.js new file mode 100644 index 0000000..e5bd561 --- /dev/null +++ b/management/univention-self-service/js/ucs/ProtectAccountAccess.js @@ -0,0 +1,345 @@ +/* + * Copyright 2015-2016 Univention GmbH + * + * http://www.univention.de/ + * + * All rights reserved. + * + * The source code of this program is made available + * under the terms of the GNU Affero General Public License version 3 + * (GNU AGPL V3) as published by the Free Software Foundation. + * + * Binary versions of this program provided by Univention to you as + * well as other copyrighted, protected or trademarked materials like + * Logos, graphics, fonts, specific documentations and configurations, + * cryptographic keys etc. are subject to a license agreement between + * you and Univention and not subject to the GNU AGPL V3. + * + * In the case you use this program under the terms of the GNU AGPL V3, + * the program is provided in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public + * License with the Debian GNU/Linux or Univention distribution in file + * /usr/share/common-licenses/AGPL-3; if not, see + * . + */ +/*global define require console window */ + +define([ + "dojo/_base/lang", + "dojo/_base/array", + "dojo/on", + "dojo/keys", + "dojo/dom", + "dojo/json", + "dojo/request/xhr", + "dijit/form/Button", + "put-selector/put", + "./ContainerWidget", + "./TextBox", + "./RadioButton", + "./lib", + "./i18n!." +], function(lang, array, on, keys, dom, json, xhr, Button, put, ContainerWidget, TextBox, RadioButton, lib, _) { + + return { + title: _('Protect Account Access'), + desc: _('Everyone forgets their password now and then. Protect yourself and activate the opportunity to set a new password.'), + hash: 'setcontactinformation', + contentContainer: null, + steps: null, + + /** + * Returns the title of the subpage. + * */ + getTitle: function() { + return _(this.title); + }, + + /** + * Returns the description of the subpage. + * */ + getDesc: function() { + return _(this.desc); + }, + + /** + * Return the content node of the subpage. + * If the content does not exists, it will be generated. + * */ + getContent: function() { + if (!this.contentContainer) { + this.contentContainer = put('div.contentWrapper'); + put(this.contentContainer, 'div.contentDesc', this.getDesc()); + put(this.contentContainer, this._getSteps()); + } + return this.contentContainer; + }, + + /** + * Return the steps for the content node. + * If the steps do not exists, they will be generated. + * Note: Please call getContent for generating the steps. + * */ + _getSteps: function() { + if (!this.steps) { + this.steps = put('ol#PasswordProtectSteps.PasswordOl'); + this._createUsername(); + this._createPassword(); + this._createSubmit(); + } + return this.steps; + }, + + /** + * Creates input field for username. + * */ + _createUsername: function() { + var step = put('li.step'); + var label = put('div.stepLabel', _('Username')); + put(step, label); + this._username = new TextBox({ + 'class': 'soloLabelPane', + isValid: function() { + return !!this.get('value'); + }, + required: true + }); + this._username.on('keyup', lang.hitch(this, function(evt) { + if (evt.keyCode === keys.ENTER) { + this._getContactInformation(); + } + })); + this._username.startup(); + put(step, this._username.domNode); + put(this.steps, step); + }, + + /** + * Creates input field for password. + * */ + _createPassword: function() { + var step = put('li.step'); + var label = put('div.stepLabel', _('Password')); + put(step, label); + this._password = new TextBox({ + 'class': 'soloLabelPane', + isValid: function() { + return !!this.get('value'); + }, + required: true, + type: 'password' + }); + this._password.on('keyup', lang.hitch(this, function(evt) { + if (evt.keyCode === keys.ENTER) { + this._getContactInformation(); + } + })); + this._password.startup(); + put(step, this._password.domNode); + put(this.steps, step); + }, + + /** + * Creates submit button. + * */ + _createSubmit: function() { + var step = put('div'); + this._showContactInformationButton = new Button({ + label: _('Next'), + onClick: lang.hitch(this, '_getContactInformation') + }); + put(step, this._showContactInformationButton.domNode); + put(this.steps, step); + }, + + /** + * Requests available renew options. + * */ + _getContactInformation: function() { + this._username.set('disabled', true); + this._password.set('disabled', true); + this._showContactInformationButton.set('disabled', true); + + var validCredentials = this._username.isValid() && this._password.isValid(); + if (validCredentials) { + data = json.stringify({ + 'username': this._username.get('value'), + 'password': this._password.get('value') + }); + xhr.post('passwordreset/get_contact', { + handleAs: 'json', + headers: { + 'Content-Type': 'application/json', + 'Accept-Language': lib.getQuery('lang') || 'en-US' + }, + data: data + }).then(lang.hitch(this, function(data) { + lib._removeMessage(); + put(this._showContactInformationButton.domNode, '.dijitHidden'); + this._createRenewOptions(data.result); + }), lang.hitch(this, function(err){ + var message = err.name + ": " + err.message; + if (err.response && err.response.data && err.response.data.message) { + message = err.response.data.message; + } + lib.showMessage({ + content: message, + 'class': '.error' + }); + this._showContactInformationButton.set('disabled', false); + this._username.set('disabled', false); + this._password.set('disabled', false); + })); + } else { + this._showContactInformationButton.set('disabled', false); + this._username.set('disabled', false); + this._password.set('disabled', false); + } + }, + + /** + * Creates renew options. + * @param {array} renewOptions - List of renew options. + * */ + _createRenewOptions: function(renewOptions) { + var options = renewOptions.length ? renewOptions : [{id: "email", value: '', label: "E-Mail"}]; + var step = put('li.step'); + this._renewOptions = step; + var label = put('div.stepLabel', _('Activate renew options.')); + put(step, label); + this._renewInputs = array.map(options, function(option) { + var optionNode = put('div'); + put(optionNode, 'div', option.label + _(' (retype)')); + var input = new TextBox({ + value: option.value + }); + var inputRetype = new TextBox({ + value: option.value, + id: option.id, + isValid: function() { + return input.get('value') === + this.get('value'); + }, + invalidMessage: _('The entries do not match, please retype again.') + }); + put(optionNode, input.domNode); + put(optionNode, inputRetype.domNode); + put(step, optionNode); + return { + id: option.id, + getValue: function() { return inputRetype.get('value');}, + isValid: function() { return inputRetype.isValid();} + }; + }); + this._saveButton = new Button({ + label: _('Save'), + onClick: lang.hitch(this, '_setContactInformation') + }); + put(step, this._saveButton.domNode); + + this._cancelButton = new Button({ + label: _('Cancel'), + onClick: lang.hitch(this, '_deleteRenewOptions') + }); + put(step, this._cancelButton.domNode); + put(this.steps, step); + }, + + /** + * Send renew options to the server. + * */ + _setContactInformation: function() { + this._cancelButton.set('disabled', true); + this._saveButton.set('disabled', true); + + var allOptionsAreValid = array.some(this._renewInputs, function(input){ + return input.isValid(); + }); + + //var isValidMail = this._validateMail(data.email); + if (allOptionsAreValid) { + data = this._getNewContactInformation(); + xhr.post('passwordreset/set_contact', { + handleAs: 'json', + headers: { + 'Content-Type': 'application/json', + 'Accept-Language': lib.getQuery('lang') || 'en-US' + }, + data: json.stringify(data) + }).then(lang.hitch(this, function(data) { + lib.showLastMessage({ + content: data.message, + 'class': '.success' + }); + this._deleteRenewOptions(); + }), lang.hitch(this, function(err){ + var message = err.name + ": " + err.message; + if (err.response && err.response.data && err.response.data.message) { + message = err.response.data.message; + } + lib.showMessage({ + content: message, + 'class': '.error' + }); + this._cancelButton.set('disabled', false); + this._saveButton.set('disabled', false); + })); + } else { + this._cancelButton.set('disabled', false); + this._saveButton.set('disabled', false); + } + }, + + /** + * Gets current renew options and credentials. + * */ + _getNewContactInformation: function() { + var contactInformation = { + 'username': this._username.get('value'), + 'password': this._password.get('value') + }; + array.forEach(this._renewInputs, function(input){ + contactInformation[input.id] = input.getValue(); + }); + + // ugly hack because the backend urgently needs an empty string + // for mail and for mobile + array.forEach(['email', 'mobile'], function(key) { + if (!contactInformation[key]) { + contactInformation[key] = ''; + } + }); + return contactInformation; + }, + + /** + * Validates given email address. + * */ + _validateMail: function(email) { + var reg = /^([\w\-]+(?:\.[\w\-]+)*)@((?:[\w\-]+\.)*\w[\w\-]{0,66})\.([a-z]{2,6}(?:\.[a-z]{2})?)$/i; + var isValid = !email.length || reg.test(email); + if(!isValid) { + lib.showMessage({ + content: _('Please enter a valid email address.'), + 'class': '.error' + }); + } + return isValid; + }, + + /** + * Delets renew options node. + * */ + _deleteRenewOptions: function() { + put(this._renewOptions, '!'); + put(this._showContactInformationButton.domNode, '!dijitHidden'); + this._showContactInformationButton.set('disabled', false); + this._username.reset(); + this._password.reset(); + } + }; +}); diff --git a/management/univention-self-service/js/ucs/TextBox.js b/management/univention-self-service/js/ucs/TextBox.js index d85ec11..fd6ca51 100644 --- a/management/univention-self-service/js/ucs/TextBox.js +++ b/management/univention-self-service/js/ucs/TextBox.js @@ -30,126 +30,18 @@ define([ "dojo/_base/declare", - "dojo/_base/lang", - "put-selector/put", - "dojo/on", - "dojo/when", - "dijit/form/ValidationTextBox", - "./LabelPane", - "./_FormWidgetMixin" - //"umc/tools" -], function(declare, lang, put, on, when, ValidationTextBox, LabelPane, _FormWidgetMixin) { - return declare("umc.widgets.TextBox", [ ValidationTextBox, _FormWidgetMixin ], { - // dynamicValue: String|Function - // Either an UMCP command to query a value from or a javascript function. - // The javascript function may return a String or a dojo/Deferred object. - dynamicValue: null, - - // depends: String?|String[]? - // Specifies that values need to be loaded dynamically depending on - // other form fields. - depends: null, - - // umcpCommand: - // Reference to the umcpCommand the widget should use. - // In order to make the widget send information such as module flavor - // etc., it can be necessary to specify a module specific umcpCommand - // method. - //umcpCommand: lang.hitch(tools, 'umcpCommand'), - - // inlineLabel: String - // If specified, the given string ias positioned as label above the input field. - inlineLabel: null, - _inlineLabelNode: null, - label: null, - - _createInlineLabelNode: function(value) { - this._inlineLabelNode = put(this.focusNode, '-span.umcInlineLabel', value); - this.own(on(this._inlineLabelNode, 'click', lang.hitch(this, 'focus'))); - }, - - reset: function() { - this.set('value', ''); - this.set('disabled', false); - this.setValid(); - if (this.inlineLabel && this._inlineLabelNode) { - this._updateInlineLabelVisibility(); - } - }, - - _updateInlineLabelVisibility: function(eventType) { - var showInlineLabel = !this.get('value') && eventType != 'keydown'; - put(this._inlineLabelNode, showInlineLabel ? '.umcEmptyValue' : '!umcEmptyValue'); - }, - - _registerInlineLabelEvents: function() { - this.on('keydown', lang.hitch(this, '_updateInlineLabelVisibility', 'keydown')); - this.on('click', lang.hitch(this, '_updateInlineLabelVisibility', 'keydown')); - this.on('focus', lang.hitch(this, '_updateInlineLabelVisibility', 'focus')); - this.on('blur', lang.hitch(this, '_updateInlineLabelVisibility', 'blur')); - }, - - _setInlineLabelAttr: function(value) { - if (!this._inlineLabelNode) { - return; - } - - // update node content - put(this._inlineLabelNode, '', { - innerHTML: value - }); - - // notify observers - this._set('inlineLabel', value); - }, + "dijit/form/ValidationTextBox" +], function(declare, ValidationTextBox) { + return declare("selfservice.password.TextBox", [ ValidationTextBox ], { buildRendering: function() { this.inherited(arguments); - if (this.inlineLabel !== null) { - this._createInlineLabelNode(this.inlineLabel); - this._registerInlineLabelEvents(); - this._updateInlineLabelVisibility(); - } - if (this.label !== undefined) { - this.label = new LabelPane({ - content: this, - 'class': this['class'] - }); - this.set('class', ''); - } this.tooltipPosition = ['after', 'below']; }, - //FIXME: the name should be different from _loadValues, e.g., _dependencyUpdate, - // and the check for all met dependencies should be done in the Form -// _loadValues: function(/*Object?*/ params) { -// // mixin additional options for the UMCP command -// if (this.dynamicOptions && typeof this.dynamicOptions == "object") { -// lang.mixin(params, this.dynamicOptions); -// } -// -// // get the dynamic values, block concurrent events for value loading -// var func = tools.stringOrFunction(this.dynamicValue, this.umcpCommand); -// var deferredOrValues = func(params); -// -// // make sure we have an array or a dojo/Deferred object -// if (deferredOrValues) { -// when(deferredOrValues, lang.hitch(this, function(res) { -// this.set('value', res); -// })); -// } -// }, - - // this seems to be necessary for IE8: - // https://forge.univention.org/bugzilla/show_bug.cgi?id=28498 - _getValueAttr: function() { - var val = this.inherited(arguments); - if (val === '') { - // seriously! at least it should not break anything... - // although val === '', json.stringify returns ""null"" in IE8 - val = ''; - } - return val; + reset: function() { + this.set('value', ''); + this.set('disabled', false); } }); }); diff --git a/management/univention-self-service/js/ucs/de.po b/management/univention-self-service/js/ucs/de.po index 7adea28..a2dce9a 100644 --- a/management/univention-self-service/js/ucs/de.po +++ b/management/univention-self-service/js/ucs/de.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: univention-apache\n" "Report-Msgid-Bugs-To: packages@univention.de\n" -"POT-Creation-Date: 2015-11-19 09:19+0100\n" +"POT-Creation-Date: 2016-04-01 13:30+0200\n" "PO-Revision-Date: 2016-01-14 11:26+0100\n" "Last-Translator: Univention GmbH \n" "Language-Team: Univention GmbH \n" @@ -12,11 +12,8 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -msgid " If you already have a token you can skip this step." -msgstr " Wenn Sie bereits über einen Token verfügen, dann können Sie diesen Schritt überspringen." - -msgid " If your token has expired you can request a new token." -msgstr " Wenn Ihr Token abgelaufen ist, können Sie einen neuen Token anfordern." +msgid " (retype)" +msgstr " (Wiederholung)" msgid "
Back to the overview." msgstr "
Zurück zur Übersicht." @@ -24,23 +21,23 @@ msgstr "
Zurück zur Übersicht." msgid "
You will be redirected {0} in {1} second(s).
" msgstr "
Sie werden in {1} Sekunden {0} weitergeleitet.
" +msgid "Activate renew options." +msgstr "Wiederherstellungsoptionen aktivieren." + msgid "Cancel" msgstr "Abbrechen" -msgid "Change Password" -msgstr "Passwort ändern" - msgid "Change password" msgstr "Passwort ändern" -msgid "Contact information for Password reset" -msgstr "Kontaktinformationen zum Zurücksetzen des Passworts" +msgid "Change your (expired) password." +msgstr "Ändern Sie Ihr (abgelaufenes) Passwort." -msgid "EMail" -msgstr "E-Mail" +msgid "Everyone forgets their password now and then. Protect yourself and activate the opportunity to set a new password." +msgstr "Jeder vergißt mal das Passwort. Schützen Sie sich und aktivieren Sie die Möglichkeit ihr Passwort erneuern zu können." -msgid "Feel free to change your contact information. Press \"Save\" to confirm your changes." -msgstr "Bitte tragen Sie Ihre Kontaktinformationen ein und drücken Sie anschließend \"Speichern\", um Ihre Änderungen zu bestätigen." +msgid "Forbidden chars:" +msgstr "Vorbotene Zeichen:" msgid "" "Forbidden redirect to: {0}\n" @@ -49,6 +46,9 @@ msgstr "" "Verbotene Weiterleitung nach: {0}\n" " Die URL muss mit (nur) einem \"/\" beginnen." +msgid "Forgot your password? Set a new one: " +msgstr "Haben Sie ihr Passwort vergessen? Setzen Sie ein Neues:" + #, python-format msgid "Hello %(last)s, %(first)s!" msgstr "Hallo %(last)s, %(first)s!" @@ -57,69 +57,69 @@ msgstr "Hallo %(last)s, %(first)s!" msgid "Hello %s %s!" msgstr "Hallo %s %s!" +msgid "If you did not received an e-mail please check your spam directory or use this link to go back to step 2." +msgstr "Sollten Sie keine E-Mail erhalten haben, dann prüfen Sie bitte Ihr SPAM-Verzeichnis oder nutzen Sie diesen Link und kehren zu Schritt 2 zurück." + msgid "Language" msgstr "Sprache" -msgid "Mobile" -msgstr "Mobilfunknummer" - -msgid "New password" +msgid "New Password" msgstr "Neues Passwort" -msgid "New password (retype)" +msgid "New Password (retype)" msgstr "Neues Passwort (Wiederholung)" msgid "Next" msgstr "Weiter" -msgid "Old password" +msgid "Old Password" msgstr "Altes Passwort" -msgid "On this page you can change your password. If you have lost your password, use this link to the password reset page." -msgstr "Auf dieser Seite können Sie Ihr Passwort ändern. Wenn Sie Ihr Passwort vergessen haben, nutzen Sie bitte den folgenden Link: Passwort zurücksetzen." - -msgid "On this page you can reset your lost password or provide contact information for setting a new password in the future." -msgstr "Auf dieser Seite können Sie Ihr Passwort zurücksetzen oder Ihre Kontaktinformationen angeben, um zukünftig Ihr Passwort zurücksetzen zu können." - -msgid "On this page you can set your contact information to reset your password in the future. During the reset process a token is sent to you. Without contact information it is not possible to reset your password." -msgstr "Auf dieser Seite können Sie Ihre Kontaktinformationen angeben. Diese Informationen werden benötigt, um Ihnen einen Token (Sicherheitsschlüssel) zuzusenden. Nur mit Hilfe eines Tokens ist es möglich das Passwort zurückzusetzen." - msgid "Password" msgstr "Passwort" -msgid "Password Reset" -msgstr "Passwort zurücksetzen" +msgid "Password change" +msgstr "Passwort ändern" -msgid "Please choose a method to receive the token." -msgstr "Bitte wählen Sie eine Benachrichtigungsart über die Sie einen Token (Sicherheitsschlüssel) erhalten möchten." +msgid "Password forgotten" +msgstr "Passwort vergessen" -msgid "Please click the following link to change your contact information for resetting your password in the future." -msgstr "Bitte nutzen Sie den folgenden Link, um Ihre Kontaktinformationen zu ändern damit Sie zukünftig Ihr Passwort zurücksetzen können." +msgid "Please choose an option to renew your password." +msgstr "Bitte wählen Sie eine Wiederherstellungsoption aus." msgid "Please enter a valid email address." msgstr "Keine gültige E-Mail-Adresse." -msgid "Please enter the token and your new password." -msgstr "Bitte geben Sie den Token (Sicherheitsschlüssel) und ein neues Passwort ein." +msgid "Protect Account Access" +msgstr "Kontozugang schützen" -msgid "Please enter your username and password to display your contact information." -msgstr "Bitte geben Sie Ihren Benutzernamen und Ihr Passwort ein, um Ihre Kontaktinformationen einsehen und ändern zu können." +msgid "Required chars:" +msgstr "Erforderliche Zeichen:" -msgid "Please provide the required data to change your password." -msgstr "Bitte geben Sie die notwendigen Daten ein, um Ihr Passwort zu ändern." +msgid "Required length:" +msgstr "Erforderliche Passwortlänge:" -msgid "Please provide your username to receive a token that is required to reset your password." -msgstr "Bitte geben Sie Ihren Benutzernamen ein. Sie erhalten anschließend einen Token (Sicherheitsschlüssel) mit dem Sie Ihr Passwort zurücksetzen können." +msgid "Required number of lower case letters:" +msgstr "Erforderliche Anzahl von Kleinbuchstaben:" -msgid "Provide your contact information." -msgstr "Geben Sie Ihre Kontaktinformationen an." +msgid "Required number of special characters (nor digit or letters):" +msgstr "Erforderliche Anzahl von Sonderzeichen:" -msgid "Reset your password." -msgstr "Passwort zurücksetzen." +msgid "Required number of upper case letters:" +msgstr "Erforderliche Anzahl von Großbuchstaben:" msgid "Save" msgstr "Speichern" +msgid "Set a new password!" +msgstr "Setzen Sie ein neues Passwort!" + +msgid "The entries do not match, please retype again." +msgstr "Die Eingaben stimmen nicht überein. Bitte versuchen Sie es erneut." + +msgid "The password must fullfill following conditions:" +msgstr "Das Passwort muss folgende Bedingungen erfüllen:" + msgid "The passwords do not match, please retype again." msgstr "Die Passwörter stimmen nicht überein. Bitte versuchen Sie es erneut." @@ -127,8 +127,8 @@ msgstr "Die Passwörter stimmen nicht überein. Bitte versuchen Sie es erneut." msgid "The total cost was %.2f EUR!" msgstr "Die Gesamtkosten waren %.2f EUR!" -msgid "Token" -msgstr "Token (Sicherheitsschlüssel)" +msgid "This value is required." +msgstr "Pflichtfeld." msgid "Translate me!" msgstr "Übersetz mich!" @@ -136,95 +136,11 @@ msgstr "Übersetz mich!" msgid "Username" msgstr "Benutzername" -msgid "to '{0}'" -msgstr "zu '{0}'" - -#~ msgid "A license file has been sent to {0}. This file is necessary to activate the system. For this, please carry out the following steps:
  1. Open the email.
  2. Save the attachement (ucs.license) on your computer.
  3. Click the button 'Upload license file'.
  4. Select the file (ucs.license) you just saved.
  5. Confirm the selection.
Once the activation has been finished your email address will be sent to the app provider. The app provider may contact you." -#~ msgstr "Eine Lizenzdatei wurde an {0} gesendet. Sie wird benötigt um das System zu aktivieren. Bitte führen Sie dazu folgende Schritte aus:
  1. Öffnen Sie die E-Mail.
  2. Speichern Sie den Anhang (ucs.license) auf Ihren Computer.
  3. Klicken Sie auf die Schaltfläche 'Lizenzdatei hochladen'.
  4. Wählen Sie die soeben gespeicherte Datei (ucs.license) aus.
  5. Bestätigen Sie die Auswahl.
Sobald die Aktivierung durchgeführt ist, wird Ihre E-Mail-Adresse an den App-Anbieter weitergeleitet. Der App-Anbieter wird Sie ggf. kontaktieren." - -#~ msgid "Activation of {appliance_name} Univention App" -#~ msgstr "Aktivierung von {appliance_name} Univention App" - -#~ msgid "Activation successful!" -#~ msgstr "Aktivierung erfolgreich!" - -#~ msgid "An unknown error has occurred." -#~ msgstr "Ein unbekannter Fehler trat auf." - -#~ msgid "An unknown error occured. Please try it again later!" -#~ msgstr "Ein unbekannter Fehler trat auf. Bitte versuchen sie es später noch einmal!" - -#~ msgid "Confirm username" -#~ msgstr "Benutzername bestätigen" - -#~ msgid "Continue" -#~ msgstr "Weiter" +msgid "We have send you an e-mail to your alternative e-mail address, that you have provided on the page \"Protect Account Access\". Please check your mails and follow the link to renew your password." +msgstr "Wir haben Ihnen eine E-Mail an Ihre alternative E-Mailadresse geschickt. Diese haben Sie auf der Seite \"Kontugang schützen\" hinterlegt. Bitte prüfen Sie Ihre E-Mails und folgen Sie den Link, um Ihr Passwort zu erneuern." -#~ msgid "E-mail address" -#~ msgstr "E-Mail-Adresse" +msgid "You have mail!" +msgstr "Sie haben eine neue E-Mail!" -#~ msgid "Error " -#~ msgstr "Fehler " - -#~ msgid "I have forgotten my password." -#~ msgstr "Ich habe mein Passwort vergessen." - -#~ msgid "I want to change my (expired) password." -#~ msgstr "Ich will mein (abgelaufenes) Passwort ändern." - -#~ msgid "I would like to set my contact information for resetting my password." -#~ msgstr "Ich möchte meine Kontaktinformationen ändern, um zukünftig mein Password zurücksetzen zu können." - -#~ msgid "If you did not receive an email, please check your SPAM directory or request the email again." -#~ msgstr "Sollten Sie keine E-Mail erhalten haben, prüfen Sie Ihr SPAM-Verzeichnis oder fordern Sie die Lizenzdatei noch einmal an." - -#~ msgid "If you encounter problems during the activation, please send an email to: feedback@univention.de" -#~ msgstr "Sollten Probleme bei der Aktivierung auftreten, senden Sie bitte eine E-Mail an: feedback@univention.de" - -#~ msgid "In order to reset your password please carry out the following steps: " -#~ msgstr "Um Ihr Passwort zurückzusetzen führen Sie bitte die folgenden Schritte aus: " - -#~ msgid "License request." -#~ msgstr "Anforderung einer Lizenz." - -#~ msgid "More details about the activation can be found in the UCS manual." -#~ msgstr "Weitere Informationen zu der Aktivierung können im UCS-Handbuch gefunden werden." - -#~ msgid "Password self-service" -#~ msgstr "Passwort verwalten" - -#~ msgid "Please enter a valid email address in order to activate {appliance_name} Univention App. The activation is mandatory to deploy the system. In the next step you can upload the license file that has been sent to your email address." -#~ msgstr "Bitte geben Sie eine gültige E-Mail-Adresse ein, um {appliance_name} Univention App zu aktivieren. Die Aktivierung ist Voraussetzung, um das System in Gebrauch zu nehmen. Im nächsten Schritt können sie die Lizenzdatei hochladen, die an Ihre E-Mail-Adresse gesendet wurde." - -#~ msgid "Please enter your username." -#~ msgstr "Bitte geben Sie Ihren Benutzernamen ein." - -#~ msgid "Request token" -#~ msgstr "Token anfordern" - -#~ msgid "Show contact information" -#~ msgstr "Kontaktinformationen anzeigen" - -#~ msgid "The following error occurred:" -#~ msgstr "Der folgende Fehler trat auf:" - -#~ msgid "The server is not responding. Please restart the system." -#~ msgstr "Der Webserver antwortet nicht. Bitte starten Sie das System neu." - -#~ msgid "Upload license file" -#~ msgstr "Lizenzdatei hochladen" - -#~ msgid "Welcome to the Password self-service. On this site you can reset and change your password. Please select an option to get more information." -#~ msgstr "Willkommen zur Passwortverwaltung. Auf dieser Seite können Sie Ihr Passwort zurücksetzen oder ändern. Bitte wählen Sie eine Option, um mehr Informationen zu erhalten." - -#~ msgid "You have got mail!" -#~ msgstr "Sie haben eine neue E-Mail!" - -#~ msgid "You have received a license file by email!" -#~ msgstr "Sie haben eine Lizendatei per E-Mail erhalten!" - -#~ msgid "your email address" -#~ msgstr "Ihre E-Mail-Adresse" - -#~ msgid "{appliance_name} Univention App is now activated. Click \"Continue\" to access the management interface (which may take a while)." -#~ msgstr "{appliance_name} Univention App ist nun aktiviert. Klicken sie auf \"Weiter\", um auf die Verwaltungsoberfläche zuzugreifen. (Das kann einige Zeit benötigen.)" +msgid "to '{0}'" +msgstr "zu '{0}'" diff --git a/management/univention-self-service/js/ucs/lib.js b/management/univention-self-service/js/ucs/lib.js index 61dcf88..4143cf3 100644 --- a/management/univention-self-service/js/ucs/lib.js +++ b/management/univention-self-service/js/ucs/lib.js @@ -36,16 +36,22 @@ define([ "dojo/io-query", "dojox/html/entities", "put-selector/put", + "dojo/request", "./i18n!." -], function(lang, fx, dom, domGeom, ioQuery, htmlEntities, put, _) { +], function(lang, fx, dom, domGeom, ioQuery, htmlEntities, put, request, _) { return { getCurrentLanguageQuery: function() { return '?lang=' + (this.getQuery('lang') || 'en-US'); }, + /** + * Displays given message. + * @param {object} msg - Provides targetNode, class and content + * for the message. + */ showMessage: function(msg) { - var targetNode = msg.targetNode || dom.byId("content"); + var targetNode = msg.targetNode || dom.byId("server_msg"); var msgNode = dom.byId('msg'); if (msgNode) { @@ -64,7 +70,7 @@ define([ }, showLastMessage: function(msg) { - var targetNode = msg.targetNode || dom.byId("title"); + var targetNode = msg.targetNode || dom.byId("server_msg"); var msgNode = dom.byId('msg'); if (msgNode) { @@ -107,22 +113,34 @@ define([ return message; }, + /** + * Returns relative url from query string. + */ _getUrlForRedirect: function() { var queryUrl = this.getQuery('url'); if (queryUrl) { - // checking if queryUrl is relative = has to start wit only one '/' - var reg = /^\/([^\/]|$)/; - var isUrlRelative = reg.test(queryUrl); - if (isUrlRelative) { + if (this._isUrlRelative(queryUrl)) { return queryUrl; } else { - // forbidden to provide absolute urls - console.error(lang.replace(_('Forbidden redirect to: {0}\n The url has to start with (only) one "/".', [queryUrl]))); + var msg = { + content: lang.replace(_('Forbidden redirect to: {0}\n The url has to start with (only) one "/".', [queryUrl])), + 'class': 'error' + }; + this.showMessage(msg); } } return; }, + /** Returns boolean if given url is relative. + * @param {string} url - url to test + * */ + _isUrlRelative: function(url) { + var reg = /^\/([^\/]|$)/; + var isUrlRelative = reg.test(url); + return isUrlRelative; + }, + _getUrlLabelForRedirect: function() { var label = this.getQuery('urlLabel'); if (label) { @@ -133,6 +151,9 @@ define([ } }, + /** + * Returns the value of the query string for a given key. + * */ getQuery: function(key) { var queryString = window.location.search.substring(1); var queryObject = ioQuery.queryToObject(queryString); @@ -146,6 +167,24 @@ define([ } }, + /** + * Returns the needed backend information for the Password Service + * as a promise or as an object. + * The information is requested once and will be cached in + * this._backend_info. + * */ + getBackendInformation: function() { + if (!this._backend_info) { + var promise = request.get("/univention-self-service/entries.json"); + promise.then(lang.hitch(this, function(data){ + this._backend_info = data; + })); + return promise; + } else { + return this._backend_info; + } + }, + wipeInNode: function(conf) { var endHeight = domGeom.getMarginBox(conf.node).h; fx.animateProperty({ diff --git a/management/univention-self-service/js/ucs/passwordchange.js b/management/univention-self-service/js/ucs/passwordchange.js deleted file mode 100644 index 864c94f..0000000 --- a/management/univention-self-service/js/ucs/passwordchange.js +++ /dev/null @@ -1,209 +0,0 @@ -/* - * Copyright 2015-2016 Univention GmbH - * - * http://www.univention.de/ - * - * All rights reserved. - * - * The source code of this program is made available - * under the terms of the GNU Affero General Public License version 3 - * (GNU AGPL V3) as published by the Free Software Foundation. - * - * Binary versions of this program provided by Univention to you as - * well as other copyrighted, protected or trademarked materials like - * Logos, graphics, fonts, specific documentations and configurations, - * cryptographic keys etc. are subject to a license agreement between - * you and Univention and not subject to the GNU AGPL V3. - * - * In the case you use this program under the terms of the GNU AGPL V3, - * the program is provided in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public - * License with the Debian GNU/Linux or Univention distribution in file - * /usr/share/common-licenses/AGPL-3; if not, see - * . - */ -/*global define require console window */ - -define([ - "dojo/_base/lang", - "dojo/on", - "dojo/keys", - "dojo/dom", - "dojo/json", - "dojo/request/xhr", - "dijit/form/Button", - "put-selector/put", - "./TextBox", - "./LabelPane", - "./lib", - "./i18n!." -], function(lang, on, keys, dom, json, xhr, Button, put, TextBox, LabelPane, lib, _) { - - return { - _createTitle: function() { - var title = _('Change Password'); - var siteDescription = lang.replace(_('On this page you can change your password. If you have lost your password, use this link to the password reset page.', [lib.getCurrentLanguageQuery()])); - document.title = title; - var titleNode = dom.byId('title'); - put(titleNode, 'h1', title); - put(titleNode, 'p', { innerHTML : siteDescription }); - put(titleNode, '!.dijitHidden'); - }, - - _createContent: function() { - var contentNode = dom.byId('content'); - var formNode = this._getFormNode(); - put(formNode, '[id=form]!dijitHidden'); - put(contentNode, formNode); - }, - - _getFormNode: function() { - var formNode = put('div.step'); - put(formNode, 'p > b', _('Please provide the required data to change your password.')); - var stepContent = put(formNode, 'div.stepContent'); - - // create input field for username - this._username = new TextBox({ - label: _('Username'), - 'class': 'doubleLabelPane block', - isValid: function() { - return !!this.get('value'); - }, - required: true - }); - put(stepContent, '>', this._username.label.domNode); - this._username.startup(); - - // create input field for old password - this._oldPassword = new TextBox({ - label: _('Old password'), - type: 'password', - 'class': 'doubleLabelPane block', - isValid: function() { - return !!this.get('value'); - }, - required: true - }); - put(stepContent, '>', this._oldPassword.label.domNode); - this._oldPassword.startup(); - - // create input fields for new password - this._newPassword = new TextBox({ - label: _('New password'), - type: 'password', - 'class': 'doubleLabelPane left', - isValid: function() { - return !!this.get('value'); - }, - required: true - }); - put(stepContent, '>', this._newPassword.label.domNode); - this._newPassword.startup(); - - // create input fields for new password - this._verifyPassword = new TextBox({ - label: _('New password (retype)'), - type: 'password', - 'class': 'doubleLabelPane', - isValid: lang.hitch(this, function() { - return this._newPassword.get('value') === - this._verifyPassword.get('value'); - }), - invalidMessage: _('The passwords do not match, please retype again.'), - required: true - }); - put(stepContent, '>', this._verifyPassword.label.domNode); - this._verifyPassword.startup(); - - // create submit button - this._submitButton = new Button({ - label: _('Change password'), - onClick: lang.hitch(this, '_submit') - }); - put(stepContent, '>', this._submitButton.domNode); - - // let the user submit form by pressing ENTER - on(document, "keyup", lang.hitch(this, function(evt) { - if (evt.keyCode === keys.ENTER && !this._submitButton.get('disabled')) { - this._submit(); - } - })); - - return formNode; - }, - - _submit: function() { - this._showValidStatusOfInputFields(); - this._submitButton.set('disabled', true); - var allInputFieldsAreValid = this._username.isValid() && - this._oldPassword.isValid() && - this._newPassword.isValid() && - this._verifyPassword.isValid(); - - if (allInputFieldsAreValid) { - data = json.stringify({ - password: { - 'username': this._username.get('value'), - 'password': this._oldPassword.get('value'), - 'new_password': this._newPassword.get('value') - } - }); - - xhr.post('/univention-management-console/set', { - handleAs: 'json', - headers: { - 'Content-Type': 'application/json', - 'Accept-Language': lib.getQuery('lang') || 'en-US' - }, - data: data - }).then(lang.hitch(this, function(data) { - lib._removeMessage(); - var callback = function() { - lib.showLastMessage({ - content: data.message, - 'class': '.success' - }); - }; - lib.wipeOutNode({ - node: dom.byId('form'), - callback: callback - }); - this._clearAllInputFields(); - }), lang.hitch(this, function(err) { - var message = err.name + ": " + err.message; - if (err.response && err.response.data && err.response.data.message) { - message = err.response.data.message; - } - lib.showMessage({content: message, 'class': '.error'}); - })).always(lang.hitch(this, function(){ - this._submitButton.set('disabled', false); - })); - } else { - this._submitButton.set('disabled', false); - } - }, - - _showValidStatusOfInputFields: function() { - this._username.setValid(this._username.isValid()); - this._oldPassword.setValid(this._oldPassword.isValid()); - this._newPassword.setValid(this._newPassword.isValid()); - //this._verifyPassword.setValid(this._verifyPassword.isValid()); - }, - - _clearAllInputFields: function() { - this._username.reset(); - this._oldPassword.reset(); - this._newPassword.reset(); - this._verifyPassword.reset(); - }, - - start: function() { - this._createTitle(); - this._createContent(); - } - }; -}); diff --git a/management/univention-self-service/js/ucs/passwordreset.js b/management/univention-self-service/js/ucs/passwordreset.js deleted file mode 100644 index b56a653..0000000 --- a/management/univention-self-service/js/ucs/passwordreset.js +++ /dev/null @@ -1,386 +0,0 @@ -/* - * Copyright 2015-2016 Univention GmbH - * - * http://www.univention.de/ - * - * All rights reserved. - * - * The source code of this program is made available - * under the terms of the GNU Affero General Public License version 3 - * (GNU AGPL V3) as published by the Free Software Foundation. - * - * Binary versions of this program provided by Univention to you as - * well as other copyrighted, protected or trademarked materials like - * Logos, graphics, fonts, specific documentations and configurations, - * cryptographic keys etc. are subject to a license agreement between - * you and Univention and not subject to the GNU AGPL V3. - * - * In the case you use this program under the terms of the GNU AGPL V3, - * the program is provided in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public - * License with the Debian GNU/Linux or Univention distribution in file - * /usr/share/common-licenses/AGPL-3; if not, see - * . - */ -/*global define require console window */ - -define([ - "dojo/_base/lang", - "dojo/_base/array", - "dojo/on", - "dojo/keys", - "dojo/dom", - "dojo/json", - "dojo/request/xhr", - "dijit/form/Button", - "put-selector/put", - "./ContainerWidget", - "./LabelPane", - "./TextBox", - "./RadioButton", - "./lib", - "./i18n!." -], function(lang, array, on, keys, dom, json, xhr, Button, put, ContainerWidget, LabelPane, TextBox, RadioButton, lib, _) { - - return { - selectedTokenMethod: null, - - _createTitle: function() { - var title = _('Password Reset'); - var siteDescription = _('On this page you can reset your lost password or provide contact information for setting a new password in the future.'); - document.title = title; - var titleNode = dom.byId('title'); - put(titleNode, 'h1', title); - put(titleNode, 'p', siteDescription); - put(titleNode, '!.dijitHidden'); - }, - - _createContent: function() { - var contentNode = dom.byId('content'); - var formNode = this._getFormNode(); - put(formNode, '[id=form].step!dijitHidden'); - put(contentNode, formNode); - this._fillContentByUrl(); - }, - - _getFormNode: function() { - var formNode = put('div[style="overflow: hidden;"]'); - - // step 1 username and link to contact information - this.usernameNode = put(formNode, 'div.step'); - put(this.usernameNode, 'p > b', _('Reset your password.')); - put(this.usernameNode, 'p', _('Please provide your username to receive a token that is required to reset your password.')); - var stepContent = put(this.usernameNode, 'div.stepContent'); - this._username = new TextBox({ - label: _('Username'), - 'class': 'soloLabelPane', - isValid: function() { - return !!this.get('value'); - }, - required: true - }); - this._username.on('keyup', lang.hitch(this, function(evt) { - if (evt.keyCode === keys.ENTER) { - this._getResetMethods(); - } - })); - put(stepContent, this._username.label.domNode); - this._username.startup(); - this._usernameButton = new Button({ - label: _('Next'), - onClick: lang.hitch(this, '_getResetMethods') - }); - put(stepContent, this._usernameButton.domNode); - - // contact information - this.contactNode = put(formNode, 'div.step'); - put(this.contactNode, 'p > b', _('Provide your contact information.')); - put(this.contactNode, 'p', { - innerHTML: lang.replace(_('Please click the following link to change your contact information for resetting your password in the future.', [lib.getCurrentLanguageQuery()])) - }); - - // step 2 token - this.tokenNode = put(formNode, 'div.step.hide-step'); - var skipStep = function() { - put(this.newPasswordNode, '!hide-step'); - put(this._requestTokenButton.domNode, '.dijitHidden'); - this._requestTokenButton.set('disabled', true); - }; - var descRequestToken = put(this.tokenNode, 'p', _('Please choose a method to receive the token.')); - put(descRequestToken, 'span', { - innerHTML: _(' If you already have a token you can skip this step.'), - onclick: lang.hitch(this, skipStep) - }); - stepContent = put(this.tokenNode, 'div.stepContent'); - this._tokenOptions = new ContainerWidget({}); - put(stepContent, this._tokenOptions.domNode); - this._requestTokenButton = new Button({ - label: _('Next'), - onClick: lang.hitch(this, '_requestToken') - }); - put(stepContent, this._requestTokenButton.domNode); - - // step 3 use the token to set a new password - this.newPasswordNode = put(formNode, 'div.step.hide-step'); - var prevStep = function() { - put(this.newPasswordNode, '.hide-step'); - put(this.tokenNode, '!dijitHidden'); - put(this.tokenNode, '!hide-step'); - put(this._requestTokenButton.domNode, '!dijitHidden'); - this._requestTokenButton.set('disabled', false); - }; - var descNewPassword = put(this.newPasswordNode, 'p', _('Please enter the token and your new password.')); - put(descNewPassword, 'span', { - innerHTML: _(' If your token has expired you can request a new token.'), - onclick: lang.hitch(this, prevStep) - }); - stepContent = put(this.newPasswordNode, 'div.stepContent'); - this._token = new TextBox({ - label: _('Token'), - 'class': 'soloLabelPane', - isValid: function() { - return !!this.get('value'); - }, - required: true - }); - this._token.on('keyup', lang.hitch(this, function(evt) { - if (evt.keyCode === keys.ENTER) { - this._setPassword(); - } - })); - put(stepContent, this._token.label.domNode); - this._token.startup(); - - this._newPassword = new TextBox({ - label: _('New password'), - type: 'password', - 'class': 'doubleLabelPane left', - isValid: function() { - return !!this.get('value'); - }, - required: true - }); - this._newPassword.on('keyup', lang.hitch(this, function(evt) { - if (evt.keyCode === keys.ENTER) { - this._setPassword(); - } - })); - put(stepContent, this._newPassword.label.domNode); - this._newPassword.startup(); - - this._verifyPassword = new TextBox({ - label: _('New password (retype)'), - type: 'password', - 'class': 'doubleLabelPane', - isValid: lang.hitch(this, function() { - return this._newPassword.get('value') === - this._verifyPassword.get('value'); - }), - invalidMessage: _('The passwords do not match, please retype again.'), - required: true - }); - this._verifyPassword.on('keyup', lang.hitch(this, function(evt) { - if (evt.keyCode === keys.ENTER) { - this._setPassword(); - } - })); - put(stepContent, this._verifyPassword.label.domNode); - this._verifyPassword.startup(); - this._setPasswordButton = new Button({ - label: _('Change password'), - onClick: lang.hitch(this, '_setPassword') - }); - put(stepContent, this._setPasswordButton.domNode); - return formNode; - }, - - _getResetMethods: function() { - this._username.set('disabled', true); - this._usernameButton.set('disabled', true); - - if (this._username.isValid()) { - data = json.stringify({ - 'username': this._username.get('value') - }); - xhr.post('passwordreset/get_reset_methods', { - handleAs: 'json', - headers: { - 'Content-Type': 'application/json', - 'Accept-Language': lib.getQuery('lang') || 'en-US' - }, - data: data - }).then(lang.hitch(this, function(data) { - lib._removeMessage(); - put(this._usernameButton.domNode, '.dijitHidden'); - put(this.contactNode, '!'); - this._buildTokenOptions(data.result); - }), lang.hitch(this, function(err){ - var message = err.name + ": " + err.message; - if (err.response && err.response.data && err.response.data.message) { - message = err.response.data.message; - } - lib.showMessage({ - content: message, - targetNode: this.usernameNode, - 'class': '.error' - }); - this._usernameButton.set('disabled', false); - this._username.set('disabled', false); - })); - } else { - this._usernameButton.set('disabled', false); - this._username.set('disabled', false); - } - }, - - _buildTokenOptions: function(options) { - array.forEach(options, lang.hitch(this, function(obj, idx){ - var radioButton = new RadioButton({ - name: 'button' + idx, - label: obj.label, - method: obj.id, - checked: idx === 0, - radioButtonGroup: 'token', - _categoryID: 'token' - }); - var label = new LabelPane({ - 'class': 'ucsRadioButtonLabel', - content: radioButton - }); - this._tokenOptions.addChild(label); - })); - put(this.tokenNode, '!hide-step'); - }, - - _requestToken: function() { - // get selected method for requesting a token - array.some(this._tokenOptions.getChildren(), lang.hitch(this, function(tokenLabel) { - var radioButton = tokenLabel.getChildren()[0]; - if (radioButton.checked) { - this.selectedTokenMethod = { - label: radioButton.get('label'), - method: radioButton.get('method') - }; - } - })); - - if (this.selectedTokenMethod) { - this._requestTokenButton.set('disabled', true); - data = json.stringify({ - 'username': this._username.get('value'), - 'method': this.selectedTokenMethod.method - }); - xhr.post('passwordreset/send_token', { - handleAs: 'json', - headers: { - 'Content-Type': 'application/json', - 'Accept-Language': lib.getQuery('lang') || 'en-US' - }, - data: data - }).then(lang.hitch(this, function(data) { - lib.showMessage({ - content: data.message, - targetNode: this.tokenNode, - 'class': '.success' - }); - put(this._requestTokenButton.domNode, '.dijitHidden'); - put(this.newPasswordNode, '!hide-step'); - }), lang.hitch(this, function(err){ - var message = err.name + ": " + err.message; - if (err.response && err.response.data && err.response.data.message) { - message = err.response.data.message; - } - lib.showMessage({ - content: message, - targetNode: this.tokenNode, - 'class': '.error' - }); - this._requestTokenButton.set('disabled', false); - })); - } - }, - - _setPassword: function() { - this._setPasswordButton.set('disabled', true); - this._token.set('disabled', true); - this._newPassword.set('disabled', true); - this._verifyPassword.set('disabled', true); - - var isTokenAndNewPassValid = this._token.isValid() && - this._newPassword.isValid() && - this._verifyPassword.isValid(); - - if (isTokenAndNewPassValid) { - data = json.stringify({ - 'username': this._username.get('value'), - 'password': this._verifyPassword.get('value'), - 'token' : this._token.get('value') - }); - xhr.post('passwordreset/set_password', { - handleAs: 'json', - headers: { - 'Content-Type': 'application/json', - 'Accept-Language': lib.getQuery('lang') || 'en-US' - }, - data: data - }).then(lang.hitch(this, function(data) { - lib._removeMessage(); - var callback = function() { - lib.showLastMessage({ - content: data.message, - 'class': '.success' - }); - }; - lib.wipeOutNode({ - node: dom.byId('form'), - callback: callback - }); - }), lang.hitch(this, function(err){ - var message = err.name + ": " + err.message; - if (err.response && err.response.data && err.response.data.message) { - message = err.response.data.message; - } - lib.showMessage({ - content: message, - targetNode: this.newPasswordNode, - 'class': '.error' - }); - this._setPasswordButton.set('disabled', false); - this._token.set('disabled', false); - this._newPassword.set('disabled', false); - this._verifyPassword.set('disabled', false); - })); - } else { - this._setPasswordButton.set('disabled', false); - this._token.set('disabled', false); - this._newPassword.set('disabled', false); - this._verifyPassword.set('disabled', false); - } - }, - - _fillContentByUrl: function() { - // checks if the url contains a username and a token - // show and fill the corresponding input fields if true - var token = lib.getQuery('token'); - var username = lib.getQuery('username'); - if (token && username) { - this._username.set('value', username); - this._token.set('value', token); - put(this.contactNode, '!'); - this._getResetMethods(); - this._requestTokenButton.set('disabled', true); - put(this.tokenNode, '.dijitHidden'); - put(this.newPasswordNode, '!hide-step'); - } - }, - - start: function() { - this._createTitle(); - this._createContent(); - } - }; -}); diff --git a/management/univention-self-service/js/ucs/setcontactinformation.js b/management/univention-self-service/js/ucs/setcontactinformation.js deleted file mode 100644 index 73b674b..0000000 --- a/management/univention-self-service/js/ucs/setcontactinformation.js +++ /dev/null @@ -1,300 +0,0 @@ -/* - * Copyright 2015-2016 Univention GmbH - * - * http://www.univention.de/ - * - * All rights reserved. - * - * The source code of this program is made available - * under the terms of the GNU Affero General Public License version 3 - * (GNU AGPL V3) as published by the Free Software Foundation. - * - * Binary versions of this program provided by Univention to you as - * well as other copyrighted, protected or trademarked materials like - * Logos, graphics, fonts, specific documentations and configurations, - * cryptographic keys etc. are subject to a license agreement between - * you and Univention and not subject to the GNU AGPL V3. - * - * In the case you use this program under the terms of the GNU AGPL V3, - * the program is provided in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public - * License with the Debian GNU/Linux or Univention distribution in file - * /usr/share/common-licenses/AGPL-3; if not, see - * . - */ -/*global define require console window */ - -define([ - "dojo/_base/lang", - "dojo/_base/array", - "dojo/on", - "dojo/keys", - "dojo/dom", - "dojo/json", - "dojo/request/xhr", - "dijit/form/Button", - "put-selector/put", - "./ContainerWidget", - "./LabelPane", - "./TextBox", - "./RadioButton", - "./lib", - "./i18n!." -], function(lang, array, on, keys, dom, json, xhr, Button, put, ContainerWidget, LabelPane, TextBox, RadioButton, lib, _) { - - return { - selectedTokenMethod: null, - - _createTitle: function() { - var title = _('Contact information for Password reset'); - var siteDescription = _('On this page you can set your contact information to reset your password in the future. During the reset process a token is sent to you. Without contact information it is not possible to reset your password.'); - document.title = title; - var titleNode = dom.byId('title'); - put(titleNode, 'h1', title); - put(titleNode, 'p', siteDescription); - put(titleNode, '!.dijitHidden'); - }, - - _createContent: function() { - var contentNode = dom.byId('content'); - var formNode = this._getFormNode(); - put(formNode, '[id=form].step!dijitHidden'); - put(contentNode, formNode); - }, - - _getFormNode: function() { - var formNode = put('div[style="overflow: hidden;"]'); - - // step 1 username and password - this.usernameNode = put(formNode, 'div.step'); - put(this.usernameNode, 'p > b', _('Please enter your username and password to display your contact information.')); - var stepContent = put(this.usernameNode, 'div.stepContent'); - - this._username = new TextBox({ - label: _('Username'), - 'class': 'doubleLabelPane left', - isValid: function() { - return !!this.get('value'); - }, - required: true - }); - this._username.on('keyup', lang.hitch(this, function(evt) { - if (evt.keyCode === keys.ENTER) { - this._getContactInformation(); - } - })); - put(stepContent, this._username.label.domNode); - this._username.startup(); - - this._password = new TextBox({ - label: _('Password'), - 'class': 'doubleLabelPane', - isValid: function() { - return !!this.get('value'); - }, - required: true, - type: 'password' - }); - this._password.on('keyup', lang.hitch(this, function(evt) { - if (evt.keyCode === keys.ENTER) { - this._getContactInformation(); - } - })); - put(stepContent, this._password.label.domNode); - this._password.startup(); - - this._showContactInformationButton = new Button({ - label: _('Next'), - onClick: lang.hitch(this, '_getContactInformation') - }); - put(stepContent, this._showContactInformationButton.domNode); - - // step 2 show and set contact information - this.contactInformationNode = put(formNode, 'div.step.hide-step'); - put(this.contactInformationNode, 'p', _('Feel free to change your contact information. Press "Save" to confirm your changes.')); - stepContent = put(this.contactInformationNode, 'div.stepContent'); - - this._email = new TextBox({ - label: _('EMail'), - 'class': 'doubleLabelPane left', - id: 'email' - }); - this._email.on('keyup', lang.hitch(this, function(evt) { - if (evt.keyCode === keys.ENTER) { - this._setContactInformation(); - } - })); - put(stepContent, this._email.label.domNode); - - this._mobile = new TextBox({ - label: _('Mobile'), - 'class': 'doubleLabelPane', - id: 'mobile' - }); - this._mobile.on('keyup', lang.hitch(this, function(evt) { - if (evt.keyCode === keys.ENTER) { - this._setContactInformation(); - } - })); - put(stepContent, this._mobile.label.domNode); - - this._saveButton = new Button({ - label: _('Save'), - onClick: lang.hitch(this, '_setContactInformation') - }); - put(stepContent, this._saveButton.domNode); - - this._cancelButton = new Button({ - label: _('Cancel'), - onClick: lang.hitch(this, '_deleteContactInformationNode') - }); - put(stepContent, this._cancelButton.domNode); - - return formNode; - }, - - _getContactInformation: function() { - this._username.set('disabled', true); - this._password.set('disabled', true); - this._showContactInformationButton.set('disabled', true); - - var validCredentials = this._username.isValid() && this._password.isValid(); - if (validCredentials) { - data = json.stringify({ - 'username': this._username.get('value'), - 'password': this._password.get('value') - }); - xhr.post('passwordreset/get_contact', { - handleAs: 'json', - headers: { - 'Content-Type': 'application/json', - 'Accept-Language': lib.getQuery('lang') || 'en-US' - }, - data: data - }).then(lang.hitch(this, function(data) { - lib._removeMessage(); - put(this._showContactInformationButton.domNode, '.dijitHidden'); - this._displayContactInformation(data.result); - }), lang.hitch(this, function(err){ - var message = err.name + ": " + err.message; - if (err.response && err.response.data && err.response.data.message) { - message = err.response.data.message; - } - lib.showMessage({ - content: message, - targetNode: this.usernameNode, - 'class': '.error' - }); - this._showContactInformationButton.set('disabled', false); - this._username.set('disabled', false); - this._password.set('disabled', false); - })); - } else { - this._showContactInformationButton.set('disabled', false); - this._username.set('disabled', false); - this._password.set('disabled', false); - } - }, - - _displayContactInformation: function(contactInformation) { - var mappingIdAndInput = { - 'email': this._email, - 'mobile': this._mobile - }; - - array.forEach(contactInformation, lang.hitch(this, function(contact){ - var currentInput = mappingIdAndInput[contact.id]; - if (currentInput) { - currentInput.set('value', contact.value); - //currentInput._updateInlineLabelVisibility(); - } - })); - put(this.contactInformationNode, '!hide-step'); - }, - - _setContactInformation: function() { - this._cancelButton.set('disabled', true); - this._saveButton.set('disabled', true); - - data = this._getNewContactInformation(); - var isValidMail = this._validateMail(data.email); - if (isValidMail) { - xhr.post('passwordreset/set_contact', { - handleAs: 'json', - headers: { - 'Content-Type': 'application/json', - 'Accept-Language': lib.getQuery('lang') || 'en-US' - }, - data: json.stringify(data) - }).then(lang.hitch(this, function(data) { - lib._removeMessage(); - var callback = function() { - lib.showLastMessage({ - content: data.message, - 'class': '.success' - }); - }; - lib.wipeOutNode({ - node: dom.byId('form'), - callback: callback - }); - }), lang.hitch(this, function(err){ - var message = err.name + ": " + err.message; - if (err.response && err.response.data && err.response.data.message) { - message = err.response.data.message; - } - lib.showMessage({ - content: message, - targetNode: this.contactInformationNode, - 'class': '.error' - }); - this._cancelButton.set('disabled', false); - this._saveButton.set('disabled', false); - })); - } else { - this._cancelButton.set('disabled', false); - this._saveButton.set('disabled', false); - } - }, - - _getNewContactInformation: function() { - var contactInformation = { - 'username': this._username.get('value'), - 'password': this._password.get('value'), - 'email': this._email.get('value'), - 'mobile': this._mobile.get('value') - }; - return contactInformation; - }, - - _validateMail: function(email) { - var reg = /^([\w-]+(?:\.[\w-]+)*)@((?:[\w-]+\.)*\w[\w-]{0,66})\.([a-z]{2,6}(?:\.[a-z]{2})?)$/i; - var isValid = !email.length || reg.test(email); - if(!isValid) { - lib.showMessage({ - content: _('Please enter a valid email address.'), - 'class': '.error', - targetNode: this.contactInformationNode - }); - } - return isValid; - }, - - _deleteContactInformationNode: function() { - put(this.contactInformationNode, '.hide-step'); - put(this._showContactInformationButton.domNode, '!dijitHidden'); - this._showContactInformationButton.set('disabled', false); - this._username.reset(); - this._password.reset(); - }, - - start: function() { - this._createTitle(); - this._createContent(); - } - }; -}); diff --git a/management/univention-self-service/scp_app_to_omar.sh b/management/univention-self-service/scp_app_to_omar.sh old mode 100755 new mode 100644 diff --git a/management/univention-self-service/umc/python/passwordreset/sending/send_with_external.py b/management/univention-self-service/umc/python/passwordreset/sending/send_with_external.py old mode 100755 new mode 100644 diff --git a/management/univention-self-service/univention-self-service b/management/univention-self-service/univention-self-service old mode 100755 new mode 100644 diff --git a/management/univention-self-service/univention-self-service-modules b/management/univention-self-service/univention-self-service-modules old mode 100755 new mode 100644 diff --git a/management/univention-self-service/univention-self-service-request-count b/management/univention-self-service/univention-self-service-request-count old mode 100755 new mode 100644 diff --git a/management/univention-self-service/www/index.html b/management/univention-self-service/www/index.html index d81fa21..8556f90 100644 --- a/management/univention-self-service/www/index.html +++ b/management/univention-self-service/www/index.html @@ -4,7 +4,7 @@ - + Password Settings @@ -16,17 +16,20 @@
-
+
+ Password Settings
-
+ +
+
+