Univention Bugzilla – Attachment 7983 Details for
Bug 42267
Integrate self service into 4.2 web structure + improve usability
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Alex Kramer's changes
42267.patch (text/plain), 114.79 KB, created by
Florian Best
on 2016-09-06 16:22:53 CEST
(
hide
)
Description:
Alex Kramer's changes
Filename:
MIME Type:
Creator:
Florian Best
Created:
2016-09-06 16:22:53 CEST
Size:
114.79 KB
patch
obsolete
>commit ed3522b4fc555672d3489f4d10e79def3fa4cf13 >Author: Florian Best <best@univention.de> >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 >+ * <http://www.gnu.org/licenses/>. >+ */ >+/*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, '</br>']); >+ 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}', ['</br>', 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 >+ * <http://www.gnu.org/licenses/>. >+ */ >+/*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 >+ * <http://www.gnu.org/licenses/>. >+ */ >+/*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 >+ * <http://www.gnu.org/licenses/>. >+ */ >+ >+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 >+ * <http://www.gnu.org/licenses/>. >+ */ >+/*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 <packages@univention.de>\n" > "Language-Team: Univention GmbH <packages@univention.de>\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 <a>skip this step</a>." >-msgstr " Wenn Sie bereits über einen Token verfügen, dann können Sie <a>diesen Schritt überspringen</a>." >- >-msgid " If your token has expired you can <a>request a new token</a>." >-msgstr " Wenn Ihr Token abgelaufen ist, können Sie einen <a>neuen Token anfordern</a>." >+msgid " (retype)" >+msgstr " (Wiederholung)" > > msgid "</br><a href='/{0}'>Back to the overview.</a>" > msgstr "</br><a href='/{0}'>Zurück zur Ãbersicht.</a>" >@@ -24,23 +21,23 @@ msgstr "</br><a href='/{0}'>Zurück zur Ãbersicht.</a>" > msgid "</br><div>You will be redirected {0} in <a id='redirectTimer'> {1} </a> second(s).</div>" > msgstr "</br><div>Sie werden in <a id='redirectTimer'> {1} </a> Sekunden {0} weitergeleitet.</div>" > >+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 <a href=\"/univention-self-service/{0}#passwordreset\">password reset</a> page." >-msgstr "Auf dieser Seite können Sie Ihr Passwort ändern. Wenn Sie Ihr Passwort vergessen haben, nutzen Sie bitte den folgenden Link: <a href=\"/univention-self-service/{0}#passwordreset\">Passwort zurücksetzen.</a>" >- >-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 <a href=\"/univention-self-service/{0}#setcontactinformation\">change your contact information</a> for resetting your password in the future." >-msgstr "Bitte nutzen Sie den folgenden Link, um Ihre <a href=\"/univention-self-service/{0}#setcontactinformation\"> Kontaktinformationen zu ändern</a> 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 <strong id=\"email-address\">{0}</strong>. This file is necessary to activate the system. For this, please carry out the following steps: <ol><li>Open the email.</li><li>Save the attachement (ucs.license) on your computer.</li><li>Click the button 'Upload license file'.</li><li>Select the file (ucs.license) you just saved.</li><li>Confirm the selection.</li></ol>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 <strong id=\"email-address\">{0}</strong> gesendet. Sie wird benötigt um das System zu aktivieren. Bitte führen Sie dazu folgende Schritte aus: <ol><li>Ãffnen Sie die E-Mail.</li><li>Speichern Sie den Anhang (ucs.license) auf Ihren Computer.</li><li>Klicken Sie auf die Schaltfläche 'Lizenzdatei hochladen'.</li><li>Wählen Sie die soeben gespeicherte Datei (ucs.license) aus.</li><li>Bestätigen Sie die Auswahl.</li></ol> 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 <a href=\"#register\"> request the email again</a>." >-#~ msgstr "Sollten Sie keine E-Mail erhalten haben, prüfen Sie Ihr SPAM-Verzeichnis oder <a href=\"#register\">fordern Sie die Lizenzdatei noch einmal an</a>." >- >-#~ msgid "If you encounter problems during the activation, please send an email to: <strong><a href=\"mailto:feedback@univention.de\" style=\"color:#000\">feedback@univention.de</a></strong>" >-#~ msgstr "Sollten Probleme bei der Aktivierung auftreten, senden Sie bitte eine E-Mail an: <strong><a href=\"mailto:feedback@univention.de\" style=\"color:#000\">feedback@univention.de</a></strong>" >- >-#~ 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 <a href=\"http://docs.univention.de/manual.html#central:license\" target=\"_blank\">UCS manual</a>." >-#~ msgstr "Weitere Informationen zu der Aktivierung können im <a href=\"http://docs.univention.de/handbuch.html#central:license\" target=\"_blank\">UCS-Handbuch</a> 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 >- * <http://www.gnu.org/licenses/>. >- */ >-/*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 <a href="/univention-self-service/{0}#passwordreset">password reset</a> 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 >- * <http://www.gnu.org/licenses/>. >- */ >-/*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 <a href="/univention-self-service/{0}#setcontactinformation">change your contact information</a> 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 <a>skip this step</a>.'), >- 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 <a>request a new token</a>.'), >- 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 >- * <http://www.gnu.org/licenses/>. >- */ >-/*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 @@ > <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> > <meta http-equiv="X-UA-Compatible" content="IE=edge" /> > <meta name="viewport" content="width=device-width, initial-scale=1.0"> >- <title></title> >+ <title>Password Settings</title> > <link rel="shortcut icon" href="/favicon.ico" /> > <link rel="stylesheet" href="js/dijit/themes/dijit.css"> > <link rel="stylesheet" href="css/bootstrap.css"/> >@@ -16,17 +16,20 @@ > <div id="wrapper"> > <div id="site-header"> > <div id="header-top"> >- <div id="header-left"> >- </div> >+ <a id="header-left" href="/ucs-overview"> >+ </a> >+ <a id="header-middle" href="/ucs-overview"></a> > <div id="header-right"> > <div class="dropdown" id="dropDownButton"></div> > </div> > </div> > </div> > <div class="container"> >- <div id="title" class="dijitHidden"> >+ <div id="title"> >+ Password Settings > </div> >- <div id="content"> >+ <div id="navigation"></div> >+ <div id="content" class="tab-content"> > <noscript> > <div> > <h1 class="no-js">Welcome to Univention Corporate Server</h1> >@@ -39,7 +42,9 @@ > </div> > </noscript> > </div> >+ <div id="server_msg"></div> > </div> >+ <div class="footer dijitHidden" id="footer"></div> > </div> > </body> > </html>
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 42267
: 7983 |
8595
|
8657