diff --git a/src/main/java/org/olat/admin/user/UserAdminController.java b/src/main/java/org/olat/admin/user/UserAdminController.java index 4c5b5d370735b4e8664f98ea42240811d8d5a98e..7632ed3ad572fee098c65d47e5c1694a4cbbab8b 100644 --- a/src/main/java/org/olat/admin/user/UserAdminController.java +++ b/src/main/java/org/olat/admin/user/UserAdminController.java @@ -201,7 +201,7 @@ public class UserAdminController extends BasicController implements Activateable //reload profile data on top myIdentity = (Identity) DBFactory.getInstance().loadObject(myIdentity); exposeUserDataToVC(ureq, myIdentity); - userProfileCtr.resetForm(ureq, getWindowControl()); + userProfileCtr.resetForm(ureq); } } } diff --git a/src/main/java/org/olat/basesecurity/BaseSecurityManager.java b/src/main/java/org/olat/basesecurity/BaseSecurityManager.java index fd8dadc02f788ee33fa1f65f723df61015206b07..5f4127402be32a0802c1a5630ee196ec6e71a443 100644 --- a/src/main/java/org/olat/basesecurity/BaseSecurityManager.java +++ b/src/main/java/org/olat/basesecurity/BaseSecurityManager.java @@ -70,7 +70,6 @@ import org.olat.portfolio.manager.InvitationDAO; import org.olat.resource.OLATResource; import org.olat.resource.OLATResourceManager; import org.olat.user.ChangePasswordController; -import org.olat.user.PersonalSettingsController; import org.olat.user.UserManager; /** @@ -205,7 +204,6 @@ public class BaseSecurityManager extends BasicManager implements BaseSecurity { createAndPersistPolicyIfNotExists(olatuserGroup, Constants.PERMISSION_HASROLE, Constants.ORESOURCE_USERS); createAndPersistPolicyIfNotExists(olatuserGroup, Constants.PERMISSION_ACCESS, OresHelper.lookupType(ChangePasswordController.class)); - createAndPersistPolicyIfNotExists(olatuserGroup, Constants.PERMISSION_ACCESS, OresHelper.lookupType(PersonalSettingsController.class)); } /** diff --git a/src/main/java/org/olat/user/HomePageDisplayController.java b/src/main/java/org/olat/user/HomePageDisplayController.java index 92a2b337ef242af0162b9bc264bac02870facade..867dffe5636c7ceb74287aca168f2de94bdc737e 100644 --- a/src/main/java/org/olat/user/HomePageDisplayController.java +++ b/src/main/java/org/olat/user/HomePageDisplayController.java @@ -49,6 +49,7 @@ import org.olat.instantMessaging.InstantMessagingService; import org.olat.instantMessaging.OpenInstantMessageEvent; import org.olat.instantMessaging.model.Buddy; import org.olat.user.propertyhandlers.UserPropertyHandler; +import org.springframework.beans.factory.annotation.Autowired; /** * Initial Date: Jul 25, 2005 @@ -62,6 +63,10 @@ public class HomePageDisplayController extends BasicController { private Link imLink; + @Autowired + private UserManager userManager; + @Autowired + private InstantMessagingModule imModule; /** * @param ureq @@ -71,11 +76,8 @@ public class HomePageDisplayController extends BasicController { public HomePageDisplayController(UserRequest ureq, WindowControl wControl, Identity homeIdentity, HomePageConfig hpc) { super(ureq, wControl); - UserManager userManager = CoreSpringFactory.getImpl(UserManager.class); - InstantMessagingModule imModule = CoreSpringFactory.getImpl(InstantMessagingModule.class); - // use property handler translator for translating of user fields - setTranslator(UserManager.getInstance().getPropertyHandlerTranslator(getTranslator())); + setTranslator(userManager.getPropertyHandlerTranslator(getTranslator())); VelocityContainer mainVC = createVelocityContainer("homepagedisplay"); String fullname = StringHelper.escapeHtml(userManager.getUserDisplayName(homeIdentity)); diff --git a/src/main/java/org/olat/user/HomePageSettingsController.java b/src/main/java/org/olat/user/HomePageSettingsController.java new file mode 100644 index 0000000000000000000000000000000000000000..9e8fb35dd773081865e69a7e957999a533db8415 --- /dev/null +++ b/src/main/java/org/olat/user/HomePageSettingsController.java @@ -0,0 +1,210 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.user; + +import java.util.List; + +import org.olat.core.gui.UserRequest; +import org.olat.core.gui.components.Component; +import org.olat.core.gui.components.form.flexible.FormItem; +import org.olat.core.gui.components.form.flexible.FormItemContainer; +import org.olat.core.gui.components.form.flexible.elements.MultipleSelectionElement; +import org.olat.core.gui.components.form.flexible.impl.FormBasicController; +import org.olat.core.gui.components.form.flexible.impl.FormEvent; +import org.olat.core.gui.components.form.flexible.impl.FormItemImpl; +import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer; +import org.olat.core.gui.control.Controller; +import org.olat.core.gui.control.WindowControl; +import org.olat.core.id.Identity; +import org.olat.user.propertyhandlers.UserPropertyHandler; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * + * Initial date: 01.07.2014<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class HomePageSettingsController extends FormBasicController { + + private static final String usageIdentifier = ProfileFormController.class.getCanonicalName(); + private static final String[] checkKeys = new String[]{ "on" }; + private static final String[] checkValues = new String[]{ "" }; + + private Identity identityToModify; + private final boolean isAdministrativeUser; + private final List<UserPropertyHandler> userPropertyHandlers; + + private HomePageFormItem previewEl; + private FormLayoutContainer previewContainer; + + @Autowired + private UserManager userManager; + @Autowired + private HomePageConfigManager hpcm; + + public HomePageSettingsController(UserRequest ureq, WindowControl wControl, + Identity identityToModify, boolean isAdministrativeUser) { + super(ureq, wControl, LAYOUT_BAREBONE); + this.identityToModify = identityToModify; + this.isAdministrativeUser = isAdministrativeUser; + setTranslator(userManager.getPropertyHandlerTranslator(getTranslator())); + userPropertyHandlers = userManager.getUserPropertyHandlersFor(usageIdentifier, isAdministrativeUser); + + initForm(ureq); + } + + public void updateIdentityToModify(UserRequest ureq, Identity identityToModify) { + this.identityToModify = identityToModify; + updatePreview(ureq); + } + + @Override + protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { + String currentGroup = null; + FormLayoutContainer groupContainer = null; + List<UserPropertyHandler> homepagePropertyHanders = userManager.getUserPropertyHandlersFor(HomePageConfig.class.getCanonicalName(), isAdministrativeUser); + + HomePageConfig conf = hpcm.loadConfigFor(identityToModify.getName()); + for (UserPropertyHandler userPropertyHandler : userPropertyHandlers) { + if (userPropertyHandler == null) { + continue; + } + + // add spacer if necessary (i.e. when group name changes) + String group = userPropertyHandler.getGroup(); + if (!group.equals(currentGroup)) { + groupContainer = FormLayoutContainer.createDefaultFormLayout("group." + group, getTranslator()); + groupContainer.setFormTitle(translate("form.group." + group)); + formLayout.add(groupContainer); + if(currentGroup == null) { + groupContainer.setFormContextHelp("org.olat.user","home-vcard.html","help.hover.vcard"); + } + currentGroup = group; + } + + if (homepagePropertyHanders.contains(userPropertyHandler)) { + // add checkbox to container if configured for homepage usage identifier + String checkboxName = userPropertyHandler.getName(); + MultipleSelectionElement publishCheckbox = uifactory.addCheckboxesHorizontal(checkboxName, + userPropertyHandler.i18nFormElementLabelKey(), + groupContainer, checkKeys , checkValues); + + boolean isEnabled = conf.isEnabled(userPropertyHandler.getName()); + publishCheckbox.select(checkKeys[0], isEnabled); + publishCheckbox.setUserObject(userPropertyHandler.getName()); + + // Mandatory homepage properties can not be changed by user + if (userManager.isMandatoryUserProperty(HomePageConfig.class.getCanonicalName(), userPropertyHandler)) { + publishCheckbox.select(checkKeys[0], true); + publishCheckbox.setEnabled(false); + } else { + publishCheckbox.addActionListener(FormEvent.ONCHANGE); + } + } + } + + String previewPage = velocity_root + "/homepage_preview.html"; + previewContainer = FormLayoutContainer.createCustomFormLayout("preview", getTranslator(), previewPage); + previewContainer.setFormTitle(translate("tab.preview")); + previewContainer.setRootForm(mainForm); + formLayout.add(previewContainer); + updatePreview(ureq); + } + + protected void updatePreview(UserRequest ureq) { + HomePageConfig conf = hpcm.loadConfigFor(identityToModify.getName()); + updatePreview(ureq, conf); + } + + protected void updatePreview(UserRequest ureq, HomePageConfig conf) { + if(previewEl != null) { + previewContainer.remove(previewEl); + removeAsListenerAndDispose(previewEl.getController()); + } + + HomePageDisplayController displayCtrl = new HomePageDisplayController(ureq, getWindowControl(), identityToModify, conf); + listenTo(displayCtrl); + previewEl = new HomePageFormItem(displayCtrl); + previewContainer.add(previewEl); + } + + @Override + protected void doDispose() { + // + } + + @Override + protected void formOK(UserRequest ureq) { + // + } + + @Override + protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) { + if(source instanceof MultipleSelectionElement) { + MultipleSelectionElement publishCheckbox = (MultipleSelectionElement)source; + if (publishCheckbox.isEnabled()) { + boolean enabled = publishCheckbox.isAtLeastSelected(1); + String propName = (String)publishCheckbox.getUserObject(); + + //load and update config + HomePageConfig conf = hpcm.loadConfigFor(identityToModify.getName()); + conf.setEnabled(propName, enabled); + hpcm.saveConfigTo(identityToModify.getName(), conf); + updatePreview(ureq, conf); + } + } + super.formInnerEvent(ureq, source, event); + } + + public class HomePageFormItem extends FormItemImpl { + + private final HomePageDisplayController previewCtrl; + + public HomePageFormItem(HomePageDisplayController previewCtrl) { + super("homepage"); + this.previewCtrl = previewCtrl; + } + + public HomePageDisplayController getController() { + return previewCtrl; + } + + @Override + protected Component getFormItemComponent() { + return previewCtrl.getInitialComponent(); + } + + @Override + protected void rootFormAvailable() { + // + } + + @Override + public void evalFormRequest(UserRequest ureq) { + // + } + + @Override + public void reset() { + // + } + } +} \ No newline at end of file diff --git a/src/main/java/org/olat/user/PersonalSettingsController.java b/src/main/java/org/olat/user/PersonalSettingsController.java deleted file mode 100644 index 9d518966cbf1b71ad20145aab788b54be037c050..0000000000000000000000000000000000000000 --- a/src/main/java/org/olat/user/PersonalSettingsController.java +++ /dev/null @@ -1,173 +0,0 @@ -/** -* OLAT - Online Learning and Training<br> -* http://www.olat.org -* <p> -* Licensed under the Apache License, Version 2.0 (the "License"); <br> -* you may not use this file except in compliance with the License.<br> -* You may obtain a copy of the License at -* <p> -* http://www.apache.org/licenses/LICENSE-2.0 -* <p> -* Unless required by applicable law or agreed to in writing,<br> -* software distributed under the License is distributed on an "AS IS" BASIS, <br> -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> -* See the License for the specific language governing permissions and <br> -* limitations under the License. -* <p> -* Copyright (c) since 2004 at Multimedia- & E-Learning Services (MELS),<br> -* University of Zurich, Switzerland. -* <hr> -* <a href="http://www.openolat.org"> -* OpenOLAT - Online Learning and Training</a><br> -* This file has been modified by the OpenOLAT community. Changes are licensed -* under the Apache 2.0 license as the original file. -*/ - -package org.olat.user; - -import java.util.List; - -import org.olat.basesecurity.Authentication; -import org.olat.basesecurity.BaseSecurity; -import org.olat.basesecurity.BaseSecurityManager; -import org.olat.basesecurity.Constants; -import org.olat.core.CoreSpringFactory; -import org.olat.core.commons.persistence.DBFactory; -import org.olat.core.commons.services.webdav.WebDAVModule; -import org.olat.core.gui.UserRequest; -import org.olat.core.gui.components.Component; -import org.olat.core.gui.components.tabbedpane.TabbedPane; -import org.olat.core.gui.components.tabbedpane.TabbedPaneChangedEvent; -import org.olat.core.gui.control.Controller; -import org.olat.core.gui.control.Event; -import org.olat.core.gui.control.WindowControl; -import org.olat.core.gui.control.controller.BasicController; -import org.olat.core.gui.control.generic.dtabs.Activateable2; -import org.olat.core.id.Identity; -import org.olat.core.id.context.ContextEntry; -import org.olat.core.id.context.StateEntry; -import org.olat.core.logging.OLATSecurityException; -import org.olat.core.util.resource.OresHelper; -import org.olat.instantMessaging.InstantMessagingModule; -import org.olat.instantMessaging.ui.IMPreferenceController; -import org.olat.ldap.LDAPLoginModule; -import org.olat.ldap.ui.LDAPAuthenticationController; -import org.olat.registration.DisclaimerController; -import org.olat.registration.RegistrationModule; - -/** - * Initial Date: Jul 29, 2003 - * - * @author Sabina Jeger - * - */ -public class PersonalSettingsController extends BasicController implements Activateable2 { - - private TabbedPane userConfig; - - private Controller ucsc; - private Controller pwdc; - private Controller hpec; - private Controller cimsc; - private Controller pwdav; - - - /** - * @param ureq - * @param wControl - */ - public PersonalSettingsController(UserRequest ureq, WindowControl wControl) { - super(ureq, wControl); - - BaseSecurity mgr = BaseSecurityManager.getInstance(); - if (!mgr.isIdentityPermittedOnResourceable( - ureq.getIdentity(), - Constants.PERMISSION_ACCESS, - OresHelper.lookupType(this.getClass()))) - throw new OLATSecurityException("Insufficient permissions to access PersonalSettingsController"); - - userConfig = new TabbedPane("userConfig", ureq.getLocale()); - //fxdiff BAKS-7 Resume function - userConfig.addListener(this); - - hpec = new ProfileAndHomePageEditController(ureq, getWindowControl(), (Identity)DBFactory.getInstance().loadObject(ureq.getIdentity()), false); - listenTo(hpec); - userConfig.addTab(translate("tab.profile"), hpec.getInitialComponent()); - - ucsc = new ChangePrefsController(ureq, getWindowControl(), (Identity)DBFactory.getInstance().loadObject(ureq.getIdentity())); - listenTo(ucsc); - userConfig.addTab(translate("tab.prefs"), ucsc.getInitialComponent()); - - if(canChangePassword()) { - pwdc = new ChangePasswordController(ureq, getWindowControl()); - listenTo(pwdc); - userConfig.addTab(translate("tab.pwd"), pwdc.getInitialComponent()); - } - - if(CoreSpringFactory.getImpl(WebDAVModule.class).isEnabled()) { - pwdav = new WebDAVPasswordController(ureq, getWindowControl()); - userConfig.addTab(translate("tab.pwdav"), pwdav.getInitialComponent()); - listenTo(pwdav); - } - - if(CoreSpringFactory.getImpl(InstantMessagingModule.class).isEnabled()){ - cimsc = new IMPreferenceController(ureq, getWindowControl(), (Identity)DBFactory.getInstance().loadObject(ureq.getIdentity())); - listenTo(cimsc); - userConfig.addTab(translate("tab.im"), cimsc.getInitialComponent()); - } - - // Show read only display of disclaimer so user sees what he accepted if disclaimer enabled - if (CoreSpringFactory.getImpl(RegistrationModule.class).isDisclaimerEnabled()) { - Controller disclaimerCtr = new DisclaimerController(ureq, getWindowControl(), true); - listenTo(disclaimerCtr); - userConfig.addTab(translate("tab.disclaimer"), disclaimerCtr.getInitialComponent()); - } - - putInitialPanel(userConfig); - - logDebug("PersonalSettingsController constructed, set velocity page to index.html", PersonalSettingsController.class.getSimpleName()); - } - - private boolean canChangePassword() { - //check if LDAP is enabled + cannot propagate password on LDAP Server - if(LDAPLoginModule.isLDAPEnabled() && !LDAPLoginModule.isPropagatePasswordChangedOnLdapServer()) { - //check if the user has a LDAP Authentication - Authentication auth = BaseSecurityManager.getInstance().findAuthentication(getIdentity(), LDAPAuthenticationController.PROVIDER_LDAP); - return auth == null;//if not in LDAP -> can change his password - } - return true; - } - - /** - * @see org.olat.core.gui.control.DefaultController#event(org.olat.core.gui.UserRequest, org.olat.core.gui.components.Component, org.olat.core.gui.control.Event) - */ - @Override - //fxdiff BAKS-7 Resume function - public void event(UserRequest ureq, Component source, Event event) { - if (source == userConfig && event instanceof TabbedPaneChangedEvent) { - userConfig.addToHistory(ureq, getWindowControl()); - } - } - - /** - * @see org.olat.core.gui.control.DefaultController#event(org.olat.core.gui.UserRequest, org.olat.core.gui.control.Controller, org.olat.core.gui.control.Event) - */ - @Override - public void event(UserRequest ureq, Controller source, Event event) { - // nothing to be done - } - - /** - * @see org.olat.core.gui.control.DefaultController#doDispose(boolean) - */ - @Override - protected void doDispose() { - // - } - - @Override - //fxdiff BAKS-7 Resume function - public void activate(UserRequest ureq, List<ContextEntry> entries, StateEntry state) { - userConfig.activate(ureq, entries, state); - } -} \ No newline at end of file diff --git a/src/main/java/org/olat/user/PortraitUploadController.java b/src/main/java/org/olat/user/PortraitUploadController.java deleted file mode 100644 index 5b3ef2b9272ea27bcd011336b41d1f0adc4d5aa3..0000000000000000000000000000000000000000 --- a/src/main/java/org/olat/user/PortraitUploadController.java +++ /dev/null @@ -1,171 +0,0 @@ -/** -* OLAT - Online Learning and Training<br> -* http://www.olat.org -* <p> -* Licensed under the Apache License, Version 2.0 (the "License"); <br> -* you may not use this file except in compliance with the License.<br> -* You may obtain a copy of the License at -* <p> -* http://www.apache.org/licenses/LICENSE-2.0 -* <p> -* Unless required by applicable law or agreed to in writing,<br> -* software distributed under the License is distributed on an "AS IS" BASIS, <br> -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> -* See the License for the specific language governing permissions and <br> -* limitations under the License. -* <p> -* Copyright (c) since 2004 at Multimedia- & E-Learning Services (MELS),<br> -* University of Zurich, Switzerland. -* <hr> -* <a href="http://www.openolat.org"> -* OpenOLAT - Online Learning and Training</a><br> -* This file has been modified by the OpenOLAT community. Changes are licensed -* under the Apache 2.0 license as the original file. -*/ -package org.olat.user; - -import java.io.File; -import java.util.HashSet; -import java.util.Set; - -import org.olat.core.commons.modules.bc.FileUploadController; -import org.olat.core.commons.modules.bc.FolderEvent; -import org.olat.core.gui.UserRequest; -import org.olat.core.gui.components.Component; -import org.olat.core.gui.components.link.Link; -import org.olat.core.gui.components.link.LinkFactory; -import org.olat.core.gui.components.velocity.VelocityContainer; -import org.olat.core.gui.control.Controller; -import org.olat.core.gui.control.Event; -import org.olat.core.gui.control.WindowControl; -import org.olat.core.gui.control.controller.BasicController; -import org.olat.core.gui.media.MediaResource; -import org.olat.core.id.Identity; -import org.olat.core.util.FileUtils; -import org.olat.core.util.vfs.LocalFolderImpl; -import org.olat.core.util.vfs.VFSContainer; - -/** - * Description: - * <p> - * This controller shows the users uploaded portrait and offers a way to upload - * a new portrait. - * <p> - * Events fired by this controller: - * <ul> - * <li>Event.DONE</li> - * <li>PORTRAIT_DELETED_EVENT</li> - * </ul> - * - * @author Alexander Schneider - */ -public class PortraitUploadController extends BasicController { - public static final Event PORTRAIT_DELETED_EVENT = new Event("portraitdeleted"); - - private VelocityContainer folderContainer; - private Link deleteButton; - private DisplayPortraitController dpc; - private FileUploadController uploadCtr; - - private Identity portraitIdent; - private File uploadDir; - private File newFile = null; - private int limitKB; // max UL limit - - private final DisplayPortraitManager dps; - - /** - * Display upload form to upload a file to the given currentPath. - * @param uploadDir - * @param wControl - * @param translator - * @param limitKB - */ - public PortraitUploadController(UserRequest ureq, WindowControl wControl, Identity portraitIdent, long limitKB) { - super(ureq, wControl); - dps = DisplayPortraitManager.getInstance(); - this.portraitIdent = portraitIdent; - this.uploadDir = dps.getPortraitDir(portraitIdent.getName()); - this.limitKB = (int) limitKB; - - folderContainer = createVelocityContainer("portraitupload"); - deleteButton = LinkFactory.createButtonSmall("command.delete", this.folderContainer, this); - - MediaResource mr = dps.getSmallPortraitResource(portraitIdent.getName()); - if (mr != null) folderContainer.contextPut("hasPortrait", Boolean.TRUE); - else folderContainer.contextPut("hasPortrait", Boolean.FALSE); - - displayPortrait(ureq, portraitIdent, true); - - // Init upload controller - Set<String> mimeTypes = new HashSet<String>(); - mimeTypes.add("image/gif"); - mimeTypes.add("image/jpg"); - mimeTypes.add("image/jpeg"); - mimeTypes.add("image/png"); - VFSContainer uploadContainer = new LocalFolderImpl(uploadDir); - uploadCtr = new FileUploadController(getWindowControl(), uploadContainer, ureq, this.limitKB, this.limitKB, mimeTypes, - false, false, false, true, false); - uploadCtr.hideTitleAndFieldset(); - listenTo(uploadCtr); - folderContainer.put("uploadCtr", uploadCtr.getInitialComponent()); - putInitialPanel(folderContainer); - } - - /** - * @see org.olat.core.gui.control.DefaultController#event(org.olat.core.gui.UserRequest, org.olat.core.gui.components.Component, org.olat.core.gui.control.Event) - */ - public void event(UserRequest ureq, Component source, Event event) { - if (source == deleteButton){ - FileUtils.deleteDirsAndFiles(uploadDir, false, false); - folderContainer.contextPut("hasPortrait", Boolean.FALSE); - uploadCtr.reset(); - fireEvent(ureq, PORTRAIT_DELETED_EVENT); - } - displayPortrait(ureq, portraitIdent, true); - } - - /** - * @see org.olat.core.gui.control.DefaultController#event(org.olat.core.gui.UserRequest, org.olat.core.gui.control.Controller, org.olat.core.gui.control.Event) - */ - public void event(UserRequest ureq, Controller source, Event event) { - if (source == uploadCtr) { - // catch upload event - if (event instanceof FolderEvent && event.getCommand().equals(FolderEvent.UPLOAD_EVENT)) { - FolderEvent folderEvent = (FolderEvent) event; - // Get file from temp folder location - String uploadFileName = folderEvent.getFilename(); - newFile = new File(uploadDir, uploadFileName); - if (!newFile.exists()) { - showError("Failed"); - } else { - dps.setPortrait(newFile, portraitIdent.getName()); - // Cleanup original file - newFile.delete(); - // And finish workflow - fireEvent(ureq, Event.DONE_EVENT); - folderContainer.contextPut("hasPortrait", Boolean.TRUE); - } - } - // redraw image - displayPortrait(ureq, portraitIdent, true); - } - } - - - private void displayPortrait(UserRequest ureq, Identity portraitIdent, boolean useLarge){ - if (dpc != null) removeAsListenerAndDispose(dpc); - dpc = new DisplayPortraitController(ureq, getWindowControl(), portraitIdent, useLarge, false); - listenTo(dpc); - folderContainer.put("portrait", dpc.getInitialComponent()); - } - - /** - * - * @see org.olat.core.gui.control.DefaultController#doDispose(boolean) - */ - protected void doDispose() { - // controllers autodisposed by basic cotntroller - } - -} diff --git a/src/main/java/org/olat/user/ProfileAndHomePageEditController.java b/src/main/java/org/olat/user/ProfileAndHomePageEditController.java index aad11b2acc863f14c5eb26c7392d690020687823..aed02babd547d88057242bb70553a2b9146743f0 100644 --- a/src/main/java/org/olat/user/ProfileAndHomePageEditController.java +++ b/src/main/java/org/olat/user/ProfileAndHomePageEditController.java @@ -25,50 +25,25 @@ package org.olat.user; -import java.text.DateFormat; -import java.util.Calendar; -import java.util.Date; -import java.util.HashMap; import java.util.List; -import java.util.Map; -import org.olat.basesecurity.BaseSecurityManager; -import org.olat.basesecurity.BaseSecurityModule; -import org.olat.core.CoreSpringFactory; -import org.olat.core.commons.persistence.DBFactory; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.Component; import org.olat.core.gui.components.link.Link; import org.olat.core.gui.components.link.LinkFactory; +import org.olat.core.gui.components.segmentedview.SegmentViewComponent; +import org.olat.core.gui.components.segmentedview.SegmentViewEvent; +import org.olat.core.gui.components.segmentedview.SegmentViewFactory; import org.olat.core.gui.components.velocity.VelocityContainer; import org.olat.core.gui.control.Controller; import org.olat.core.gui.control.Event; import org.olat.core.gui.control.WindowControl; import org.olat.core.gui.control.controller.BasicController; -import org.olat.core.gui.control.generic.closablewrapper.CloseableModalController; -import org.olat.core.gui.control.generic.modal.DialogBoxController; -import org.olat.core.gui.control.generic.modal.DialogBoxUIFactory; -import org.olat.core.gui.translator.Translator; -import org.olat.core.helpers.Settings; +import org.olat.core.gui.control.generic.dtabs.Activateable2; import org.olat.core.id.Identity; -import org.olat.core.id.User; -import org.olat.core.util.Util; -import org.olat.core.util.WebappHelper; -import org.olat.core.util.coordinate.CoordinatorManager; -import org.olat.core.util.coordinate.SyncerExecutor; -import org.olat.core.util.event.MultiUserEvent; -import org.olat.core.util.mail.MailBundle; -import org.olat.core.util.mail.MailManager; -import org.olat.core.util.mail.MailerResult; -import org.olat.core.util.resource.OresHelper; +import org.olat.core.id.context.ContextEntry; +import org.olat.core.id.context.StateEntry; import org.olat.login.SupportsAfterLoginInterceptor; -import org.olat.registration.RegistrationManager; -import org.olat.registration.TemporaryKey; -import org.olat.registration.TemporaryKeyImpl; - -import com.thoughtworks.xstream.XStream; - -import de.bps.olat.user.ChangeEMailController; /** * Initial Date: Jul 14, 2005 @@ -77,36 +52,19 @@ import de.bps.olat.user.ChangeEMailController; * * Comment: */ -public class ProfileAndHomePageEditController extends BasicController implements SupportsAfterLoginInterceptor { - - private static final String VELOCITY_ROOT = Util.getPackageVelocityRoot(ProfileAndHomePageEditController.class); - private static final long UPLOAD_LIMIT_KB = 500; - - private VelocityContainer myContent; - private Link previewButton; +public class ProfileAndHomePageEditController extends BasicController implements Activateable2, SupportsAfterLoginInterceptor { - private Translator translator; + private final VelocityContainer myContent; + private final Link profilLink, homePageLink; + private final SegmentViewComponent segmentView; + private ProfileFormController profileFormController; + private HomePageSettingsController homePageController; - protected ProfileFormController profileFormController; - private Component profileFormControllerComponent; - private HomePageConfigManager hpcm = HomePageConfigManagerImpl.getInstance(); - private PortraitUploadController portraitUploadController; - private Controller hpDispC; - private CloseableModalController clc; - protected Identity identityToModify; - protected HomePageConfig homePageConfig; - private DialogBoxController dialogCtr; - private final MailManager mailManager; - private RegistrationManager rm = RegistrationManager.getInstance(); - private static String SEPARATOR = "\n____________________________________________________________________\n"; - - private boolean emailChanged = false; - protected String changedEmail; - protected String currentEmail; + private Identity identityToModify; private boolean isAdministrativeUser; public ProfileAndHomePageEditController(UserRequest ureq, WindowControl wControl) { - this(ureq,wControl,ureq.getIdentity(),ureq.getUserSession().getRoles().isOLATAdmin()); + this(ureq,wControl, ureq.getIdentity(), ureq.getUserSession().getRoles().isOLATAdmin()); } /** @@ -120,271 +78,99 @@ public class ProfileAndHomePageEditController extends BasicController implements super(ureq, wControl); this.identityToModify = identityToModify; this.isAdministrativeUser = isAdministrativeUser; - this.translator = Util.createPackageTranslator(ProfileAndHomePageEditController.class, ureq.getLocale()); - this.translator = UserManager.getInstance().getPropertyHandlerTranslator(this.translator); - mailManager = CoreSpringFactory.getImpl(MailManager.class); - - this.myContent = new VelocityContainer("homepage", VELOCITY_ROOT + "/homepage.html", this.translator, this); - this.previewButton = LinkFactory.createButtonSmall("command.preview", this.myContent, this); - previewButton.setIconLeftCSS("o_icon o_icon_preview"); - this.homePageConfig = this.hpcm.loadConfigFor(this.identityToModify.getName()); - - this.profileFormController = new ProfileFormController(ureq, wControl, this.homePageConfig, this.identityToModify, isAdministrativeUser); - listenTo(this.profileFormController); - this.profileFormControllerComponent = this.profileFormController.getInitialComponent(); - this.myContent.put("homepageform", this.profileFormControllerComponent); - - this.portraitUploadController = new PortraitUploadController(ureq, getWindowControl(), this.identityToModify, UPLOAD_LIMIT_KB); - listenTo(this.portraitUploadController); + setTranslator(UserManager.getInstance().getPropertyHandlerTranslator(getTranslator())); + + myContent = createVelocityContainer("homepage"); + segmentView = SegmentViewFactory.createSegmentView("segments", myContent, this); + profilLink = LinkFactory.createLink("tab.profile", myContent, this); + profilLink.setElementCssClass("o_sel_usersettings_profile"); + segmentView.addSegment(profilLink, true); + homePageLink = LinkFactory.createLink("tab.hp", myContent, this); + homePageLink.setElementCssClass("o_sel_usersettings_homepage"); + segmentView.addSegment(homePageLink, false); + + putInitialPanel(myContent); + } - Component c = this.portraitUploadController.getInitialComponent(); - this.myContent.put("c", c); - putInitialPanel(this.myContent); + @Override + protected void doDispose() { + // controllers disposed by basic controller } @Override public boolean isInterceptionRequired(UserRequest ureq) { if (ureq.getUserSession().getRoles() == null || ureq.getUserSession().getRoles().isInvitee() - || ureq.getUserSession().getRoles().isGuestOnly()) return false; - else return true; + || ureq.getUserSession().getRoles().isGuestOnly()) { + return false; + } else { + return true; + } } - /** - * @see org.olat.core.gui.control.DefaultController#event(org.olat.core.gui.UserRequest, - * org.olat.core.gui.components.Component, - * org.olat.core.gui.control.Event) - */ @Override public void event(UserRequest ureq, Component source, Event event) { - if (source == this.previewButton) { - if (this.hpDispC != null) removeAsListenerAndDispose(this.hpDispC); - hpDispC = new HomePageDisplayController(ureq, getWindowControl(), identityToModify, homePageConfig); - listenTo(hpDispC); - if (clc != null) removeAsListenerAndDispose(clc); - clc = new CloseableModalController(getWindowControl(), this.translator.translate("command.closehp"), this.hpDispC - .getInitialComponent()); - listenTo(clc); - clc.activate(); + if(source == segmentView) { + if(event instanceof SegmentViewEvent) { + SegmentViewEvent sve = (SegmentViewEvent)event; + String segmentCName = sve.getComponentName(); + Component clickedLink = myContent.getComponent(segmentCName); + Controller selectedController = null; + if (clickedLink == profilLink) { + selectedController = doOpenProfile(ureq); + } else if (clickedLink == homePageLink){ + selectedController = doOpenHomePageSettings(ureq); + } + addToHistory(ureq, selectedController); + } } } - /** - * @see org.olat.core.gui.control.DefaultController#event(org.olat.core.gui.UserRequest, - * org.olat.core.gui.control.Controller, org.olat.core.gui.control.Event) - */ @Override - protected void event(final UserRequest ureq, Controller source, Event event) { - super.event(ureq, source, event); - if (source == this.portraitUploadController) { - if (event.equals(Event.DONE_EVENT) || event.getCommand().equals(PortraitUploadController.PORTRAIT_DELETED_EVENT.getCommand())) { - // should not fire event, as only needed to update identity if useradmin changed it. portrait doesnt change identity and is not shown in table. - // see UserAdminController -// fireEvent(ureq, Event.DONE_EVENT); - } - } else if (source == this.profileFormController) { - if (event == Event.DONE_EVENT) { - // get the new values from the form - this.profileFormController.updateFromFormData(this.homePageConfig, this.identityToModify); - - // update the home page configuration - this.hpcm.saveConfigTo(this.identityToModify.getName(), this.homePageConfig); - - // update the portrait upload (gender specific image) - if (portraitUploadController != null) removeAsListenerAndDispose(portraitUploadController); - portraitUploadController = new PortraitUploadController(ureq, getWindowControl(), this.identityToModify, UPLOAD_LIMIT_KB); - listenTo(this.portraitUploadController); - this.myContent.put("c", this.portraitUploadController.getInitialComponent()); - - // fire the appropriate event - fireEvent(ureq, Event.DONE_EVENT); - - // update the user profile data - CoordinatorManager.getInstance().getCoordinator().getSyncer().doInSync( - OresHelper.createOLATResourceableInstance(Identity.class, ProfileAndHomePageEditController.this.identityToModify.getKey()), new SyncerExecutor() { - @SuppressWarnings("synthetic-access") - public void execute() { - UserManager um = UserManager.getInstance(); - ProfileAndHomePageEditController.this.identityToModify = (Identity) DBFactory.getInstance().loadObject(ProfileAndHomePageEditController.this.identityToModify); - currentEmail = ProfileAndHomePageEditController.this.identityToModify.getUser().getProperty("email", null); - - ProfileAndHomePageEditController.this.identityToModify = profileFormController - .updateIdentityFromFormData(ProfileAndHomePageEditController.this.identityToModify); - changedEmail = ProfileAndHomePageEditController.this.identityToModify.getUser().getProperty("email", null); - if (!currentEmail.equals(changedEmail)) { - // allow an admin to change email without verification workflow. usermanager is only permitted to do so, if set by config. - if ( !(ureq.getUserSession().getRoles().isOLATAdmin() || ( BaseSecurityModule.USERMANAGER_CAN_BYPASS_EMAILVERIFICATION && ureq.getUserSession().getRoles().isUserManager() ))) { - emailChanged = true; - // change email address to old address until it is verified - ProfileAndHomePageEditController.this.identityToModify.getUser().setProperty("email", currentEmail); - } else { - // fxdiff: FXOLAT-44 delete previous change-workflows - String key = ProfileAndHomePageEditController.this.identityToModify.getUser().getProperty("emchangeKey", null); - TemporaryKeyImpl tempKey = rm.loadTemporaryKeyByRegistrationKey(key); - if (tempKey != null) { - rm.deleteTemporaryKey(tempKey); - } - } - } - if (!um.updateUserFromIdentity(ProfileAndHomePageEditController.this.identityToModify)) { - getWindowControl().setInfo(translate("profile.unsuccessful")); - // reload user data from db - ProfileAndHomePageEditController.this.identityToModify = BaseSecurityManager.getInstance().loadIdentityByKey( - ProfileAndHomePageEditController.this.identityToModify.getKey()); - } - CoordinatorManager.getInstance().getCoordinator().getEventBus().fireEventToListenersOf(new MultiUserEvent("changed"), - OresHelper.createOLATResourceableInstance(Identity.class, ProfileAndHomePageEditController.this.identityToModify.getKey())); - if (!emailChanged) resetForm(ureq, getWindowControl()); - } - }); - if (emailChanged) { - if (dialogCtr != null) { - dialogCtr.dispose(); - } - String changerEMail = ureq.getIdentity().getUser().getProperty("email", ureq.getLocale()); - String dialogText = ""; - if(changerEMail != null && changerEMail.length() > 0 && changerEMail.equals(currentEmail)) { - dialogText = translate("email.change.dialog.text"); - } else { - dialogText = translate("email.change.dialog.text.usermanager"); - } - dialogCtr = DialogBoxUIFactory.createYesNoDialog(ureq, getWindowControl(), translate("email.change.dialog.title"), dialogText); - dialogCtr.addControllerListener(this); - dialogCtr.activate(); - } + protected void event(UserRequest ureq, Controller source, Event event) { + if(profileFormController == source) { + identityToModify = profileFormController.getIdentityToModify(); + if(Event.FAILED_EVENT.equals(event)) { + resetForm(ureq); } - } else if (source == dialogCtr) { - dialogCtr.dispose(); - dialogCtr = null; - if (DialogBoxUIFactory.isYesEvent(event)) { - if (changedEmail != null) { - createChangeEmailWorkflow(ureq); - } + if(homePageController != null) { + homePageController.updateIdentityToModify(ureq, identityToModify); } - resetForm(ureq, getWindowControl()); } + super.event(ureq, source, event); } - private void createChangeEmailWorkflow(UserRequest ureq) { - // send email - changedEmail = changedEmail.trim(); - String body = null; - String subject = null; - // get remote address - String ip = ureq.getHttpReq().getRemoteAddr(); - String today = DateFormat.getDateInstance(DateFormat.LONG, ureq.getLocale()).format(new Date()); - // mailer configuration - String serverpath = Settings.getServerContextPathURI(); - String servername = ureq.getHttpReq().getServerName(); - - logDebug("this servername is " + servername + " and serverpath is " + serverpath, null); - // load or create temporary key - Map<String, String> mailMap = new HashMap<String, String>(); - mailMap.put("currentEMail", currentEmail); - mailMap.put("changedEMail", changedEmail); - - XStream xml = new XStream(); - String serMailMap = xml.toXML(mailMap); - - TemporaryKey tk = loadCleanTemporaryKey(serMailMap); - if (tk == null) { - tk = rm.createTemporaryKeyByEmail(serMailMap, ip, RegistrationManager.EMAIL_CHANGE); - } else { - rm.deleteTemporaryKeyWithId(tk.getRegistrationKey()); - tk = rm.createTemporaryKeyByEmail(serMailMap, ip, RegistrationManager.EMAIL_CHANGE); - } - - // create date, time string - Calendar cal = Calendar.getInstance(); - cal.setTime(tk.getCreationDate()); - cal.add(Calendar.DAY_OF_WEEK, ChangeEMailController.TIME_OUT); - String time = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, ureq.getLocale()).format(cal.getTime()); - // create body and subject for email - body = this.translator.translate("email.change.body", new String[] { serverpath + "/dmz/emchange/index.html?key=" + tk.getRegistrationKey() + "&lang=" + ureq.getLocale().getLanguage(), time, currentEmail, changedEmail }) - + SEPARATOR + this.translator.translate("email.change.wherefrom", new String[] { serverpath, today, ip }); - subject = translate("email.change.subject"); - // send email - try { - - MailBundle bundle = new MailBundle(); - bundle.setFrom(WebappHelper.getMailConfig("mailReplyTo")); - bundle.setTo(changedEmail); - bundle.setContent(subject, body); - - MailerResult result = mailManager.sendMessage(bundle); - boolean isMailSent = result.isSuccessful(); - if (isMailSent) { - tk.setMailSent(true); - // set key - User user = this.identityToModify.getUser(); - user.setProperty("emchangeKey", tk.getRegistrationKey()); - UserManager.getInstance().updateUser(user); - getWindowControl().setInfo(this.translator.translate("email.sent")); - } else { - tk.setMailSent(false); - rm.deleteTemporaryKeyWithId(tk.getRegistrationKey()); - getWindowControl().setError(this.translator.translate("email.notsent")); - } - } catch (Exception e) { - rm.deleteTemporaryKeyWithId(tk.getRegistrationKey()); - getWindowControl().setError(translator.translate("email.notsent")); - } + public void resetForm(UserRequest ureq) { + removeAsListenerAndDispose(profileFormController); + removeAsListenerAndDispose(homePageController); + profileFormController = null; + homePageController = null; + doOpenProfile(ureq); } - /** - * Load and clean temporary keys with action "EMAIL_CHANGE". - * @param serMailMap - * @return - */ - private TemporaryKey loadCleanTemporaryKey(String serMailMap) { - TemporaryKey tk = rm.loadTemporaryKeyByEmail(serMailMap); - if (tk == null) { - XStream xml = new XStream(); - @SuppressWarnings("unchecked") - Map<String, String> mails = (Map<String, String>) xml.fromXML(serMailMap); - String currentEMail = mails.get("currentEMail"); - List<TemporaryKey> tks = rm.loadTemporaryKeyByAction(RegistrationManager.EMAIL_CHANGE); - if (tks != null) { - synchronized (tks) { - tks = rm.loadTemporaryKeyByAction(RegistrationManager.EMAIL_CHANGE); - int countCurrentEMail = 0; - for (TemporaryKey temporaryKey : tks) { - @SuppressWarnings("unchecked") - Map<String, String> tkMails = (Map<String, String>) xml.fromXML(temporaryKey.getEmailAddress()); - if (tkMails.get("currentEMail").equals(currentEMail)) { - if (countCurrentEMail > 0) { - // clean - rm.deleteTemporaryKeyWithId(temporaryKey.getRegistrationKey()); - } else { - // load - tk = temporaryKey; - } - countCurrentEMail++; - } - } - } - } + @Override + public void activate(UserRequest ureq, List<ContextEntry> entries, StateEntry state) { + if(entries == null || entries.isEmpty()) { + doOpenProfile(ureq); } - return tk; } + private ProfileFormController doOpenProfile(UserRequest ureq) { + if(profileFormController == null) { + profileFormController = new ProfileFormController(ureq, getWindowControl(), identityToModify, isAdministrativeUser); + listenTo(profileFormController); + } - /** - * - * @see org.olat.core.gui.control.DefaultController#doDispose(boolean) - */ - @Override - protected void doDispose() { - // controllers disposed by basic controller + myContent.put("segmentCmp", profileFormController.getInitialComponent()); + return profileFormController; } - - public void resetForm(UserRequest ureq, WindowControl wControl) { - if (this.profileFormController != null) { - this.myContent.remove(this.profileFormControllerComponent); - removeAsListenerAndDispose(this.profileFormController); + + private HomePageSettingsController doOpenHomePageSettings(UserRequest ureq) { + if(homePageController == null) { + homePageController = new HomePageSettingsController(ureq, getWindowControl(), identityToModify, isAdministrativeUser); + listenTo(homePageController); } - this.profileFormController = new ProfileFormController(ureq, wControl, this.homePageConfig, this.identityToModify, isAdministrativeUser); - listenTo(this.profileFormController); - this.profileFormControllerComponent = this.profileFormController.getInitialComponent(); - this.myContent.put("homepageform", this.profileFormControllerComponent); + + myContent.put("segmentCmp", homePageController.getInitialComponent()); + return homePageController; } } diff --git a/src/main/java/org/olat/user/ProfileFormController.java b/src/main/java/org/olat/user/ProfileFormController.java index 9e188d4530b1110e1fbeaa4968ca917caf4f5cd7..dc48d354127ece3513ba10f60a883bb6688c6d7c 100644 --- a/src/main/java/org/olat/user/ProfileFormController.java +++ b/src/main/java/org/olat/user/ProfileFormController.java @@ -20,32 +20,59 @@ package org.olat.user; +import java.io.File; +import java.text.DateFormat; +import java.util.Calendar; +import java.util.Date; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import org.olat.basesecurity.BaseSecurityManager; +import org.olat.basesecurity.BaseSecurityModule; +import org.olat.core.commons.persistence.DBFactory; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.form.flexible.FormItem; import org.olat.core.gui.components.form.flexible.FormItemContainer; +import org.olat.core.gui.components.form.flexible.elements.FileElement; +import org.olat.core.gui.components.form.flexible.elements.FormLink; import org.olat.core.gui.components.form.flexible.elements.MultipleSelectionElement; import org.olat.core.gui.components.form.flexible.elements.RichTextElement; import org.olat.core.gui.components.form.flexible.elements.TextElement; import org.olat.core.gui.components.form.flexible.impl.FormBasicController; +import org.olat.core.gui.components.form.flexible.impl.FormEvent; import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer; -import org.olat.core.gui.components.velocity.VelocityContainer; +import org.olat.core.gui.components.link.Link; import org.olat.core.gui.control.Controller; import org.olat.core.gui.control.Event; import org.olat.core.gui.control.WindowControl; +import org.olat.core.gui.control.generic.modal.DialogBoxController; +import org.olat.core.gui.control.generic.modal.DialogBoxUIFactory; +import org.olat.core.helpers.Settings; import org.olat.core.id.Identity; +import org.olat.core.id.OLATResourceable; import org.olat.core.id.User; +import org.olat.core.util.WebappHelper; +import org.olat.core.util.coordinate.CoordinatorManager; +import org.olat.core.util.coordinate.SyncerExecutor; +import org.olat.core.util.event.MultiUserEvent; +import org.olat.core.util.mail.MailBundle; +import org.olat.core.util.mail.MailManager; +import org.olat.core.util.mail.MailerResult; +import org.olat.core.util.resource.OresHelper; import org.olat.core.util.xml.XStreamHelper; import org.olat.registration.RegistrationManager; +import org.olat.registration.TemporaryKey; import org.olat.registration.TemporaryKeyImpl; import org.olat.user.propertyhandlers.UserPropertyHandler; +import org.springframework.beans.factory.annotation.Autowired; import com.thoughtworks.xstream.XStream; +import de.bps.olat.user.ChangeEMailController; + /** * Provides a controller which lets the user edit their user profile and choose * the fields which are made publicly visible. @@ -55,24 +82,36 @@ import com.thoughtworks.xstream.XStream; */ public class ProfileFormController extends FormBasicController { - private HomePageConfig conf; - - private List<UserPropertyHandler> userPropertyHandlers; - - private Map<String, FormItem> formItems; - - private Map<String, String> formContext; + private static final String usageIdentifier= ProfileFormController.class.getCanonicalName(); + private static final String SEPARATOR = "\n____________________________________________________________________\n"; + private final Map<String, FormItem> formItems = new HashMap<String, FormItem>(); + private final Map<String, String> formContext = new HashMap<String, String>(); private RichTextElement textAboutMe; - private String usageIdentifier; - - private Map<String, MultipleSelectionElement> publishCheckboxes; - - private Identity identity; - - private boolean isAdministrativeUser; - + private Identity identityToModify; + private DialogBoxController dialogCtr; + + private FormLink deletePortrait; + private FileElement portraitUpload; + + private final boolean isAdministrativeUser; + private final List<UserPropertyHandler> userPropertyHandlers; + + private boolean emailChanged = false; + private String changedEmail; + private String currentEmail; + + @Autowired + private UserManager userManager; + @Autowired + private RegistrationManager rm; + @Autowired + private MailManager mailManager; + @Autowired + private HomePageConfigManager hpcm; + @Autowired + private DisplayPortraitManager dps; /** * Creates this controller. @@ -85,71 +124,39 @@ public class ProfileFormController extends FormBasicController { * @param isAdministrativeUser true: user is editing another users profile as * user manager; false: use is editing his own profile */ - public ProfileFormController(UserRequest ureq, WindowControl wControl, HomePageConfig conf, Identity identity, - boolean isAdministrativeUser) { - super(ureq, wControl, "combinedform"); - UserManager um = UserManager.getInstance(); - setTranslator(um.getPropertyHandlerTranslator(getTranslator())); - this.publishCheckboxes = new HashMap<String, MultipleSelectionElement>(); - this.conf = conf; - this.usageIdentifier = ProfileFormController.class.getCanonicalName(); - this.userPropertyHandlers = um.getUserPropertyHandlersFor(this.usageIdentifier, isAdministrativeUser); - this.identity = identity; - this.formItems = new HashMap<String, FormItem>(); - this.formContext = new HashMap<String, String>(); + public ProfileFormController(UserRequest ureq, WindowControl wControl, + Identity identityToModify, boolean isAdministrativeUser) { + super(ureq, wControl, LAYOUT_BAREBONE); + setTranslator(userManager.getPropertyHandlerTranslator(getTranslator())); + + this.identityToModify = identityToModify; this.isAdministrativeUser = isAdministrativeUser; + + userPropertyHandlers = userManager.getUserPropertyHandlersFor(usageIdentifier, isAdministrativeUser); initForm(ureq); } + + public Identity getIdentityToModify() { + return identityToModify; + } /** * @see org.olat.core.gui.components.form.flexible.impl.FormBasicController#doDispose() */ @Override protected void doDispose() { - // nothing to dispose. - - } - - /** - * @see org.olat.core.gui.components.form.flexible.impl.FormBasicController#formOK(org.olat.core.gui.UserRequest) - */ - @Override - protected void formOK(UserRequest ureq) { - fireEvent(ureq, Event.DONE_EVENT); + // nothing to dispose. } - /** - * @see org.olat.core.gui.components.form.flexible.impl.FormBasicController#formNOK(org.olat.core.gui.UserRequest) - */ - @Override - protected void formNOK(UserRequest ureq) { - fireEvent(ureq, Event.FAILED_EVENT); - } - - /** - * @see org.olat.core.gui.components.form.flexible.impl.FormBasicController#formCancelled(org.olat.core.gui.UserRequest) - */ - @Override - protected void formCancelled(UserRequest ureq) { - fireEvent(ureq, Event.CANCELLED_EVENT); - } - - /* - * (non-Javadoc) - * - * @see - * org.olat.core.gui.components.form.flexible.impl.FormBasicController#initForm - * (org.olat.core.gui.components.form.flexible.FormItemContainer, - * org.olat.core.gui.control.Controller, org.olat.core.gui.UserRequest) - */ @Override protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { - formContext.put("username", identity.getName()); - + String currentGroup = null; + User user = identityToModify.getUser(); + // show a form element for each property handler FormLayoutContainer groupContainer = null; - for (UserPropertyHandler userPropertyHandler : this.userPropertyHandlers) { + for (UserPropertyHandler userPropertyHandler : userPropertyHandlers) { if (userPropertyHandler == null) { continue; } @@ -159,45 +166,27 @@ public class ProfileFormController extends FormBasicController { if (!group.equals(currentGroup)) { groupContainer = FormLayoutContainer.createDefaultFormLayout("group." + group, getTranslator()); groupContainer.setFormTitle(translate("form.group." + group)); - this.formItems.put("group." + group, groupContainer); + formItems.put("group." + group, groupContainer); formLayout.add(groupContainer); + if(currentGroup == null) { + groupContainer.setFormContextHelp("org.olat.user","home-vcard.html","help.hover.vcard"); + } currentGroup = group; } -// if (homepagePropertyHanders.contains(userPropertyHandler)) { -// // add checkbox to container if configured for homepage usage identifier -// String checkboxName = "checkbox_" + userPropertyHandler.getName(); -// MultipleSelectionElement publishCheckbox = uifactory.addCheckboxesHorizontal(checkboxName, null, groupContainer, new String[] {userPropertyHandler.i18nFormElementLabelKey()}, new String[] {""}, null); -// this.publishCheckboxes.put(checkboxName, publishCheckbox); -// boolean isEnabled = this.conf.isEnabled(userPropertyHandler.getName()); -// if (isEnabled) { -// publishCheckbox.select(userPropertyHandler.i18nFormElementLabelKey(), true); -// } else { -// publishCheckbox.select(userPropertyHandler.i18nFormElementLabelKey(), false); -// } -// // Mandatory homepage properties can not be changed by user -// UserManager um = UserManager.getInstance(); -// if (um.isMandatoryUserProperty(HomePageConfig.class.getCanonicalName(), userPropertyHandler)) { -// publishCheckbox.select(userPropertyHandler.i18nFormElementLabelKey(), true); -// publishCheckbox.setEnabled(false); -// } -// } else { -// uifactory.addSpacerElement("spacer_" + userPropertyHandler.getName(), groupContainer, true); -// } - // add input field to container - FormItem formItem = userPropertyHandler.addFormItem(getLocale(), identity.getUser(), this.usageIdentifier, this.isAdministrativeUser, groupContainer); + FormItem formItem = userPropertyHandler.addFormItem(getLocale(), user, usageIdentifier, isAdministrativeUser, groupContainer); String propertyName = userPropertyHandler.getName(); - this.formItems.put(propertyName, formItem); + formItems.put(propertyName, formItem); if (formItem instanceof TextElement) { // it's a text field, so get the value of this property into the text field TextElement textElement = (TextElement)formItem; - textElement.setValue(this.identity.getUser().getProperty(propertyName, getLocale())); + textElement.setValue(user.getProperty(propertyName, getLocale())); } else if (formItem instanceof MultipleSelectionElement) { // it's a checkbox, so set the box to checked if the corresponding property is set to "true" MultipleSelectionElement checkbox = (MultipleSelectionElement)formItem; - String value = this.identity.getUser().getProperty(propertyName, getLocale()); + String value = user.getProperty(propertyName, getLocale()); if (value != null) { checkbox.select(propertyName, value.equals("true")); } else { @@ -209,7 +198,7 @@ public class ProfileFormController extends FormBasicController { // special case for email field if (userPropertyHandler.getName().equals("email")) { RegistrationManager rm = RegistrationManager.getInstance(); - String key = this.identity.getUser().getProperty("emchangeKey", null); + String key = user.getProperty("emchangeKey", null); TemporaryKeyImpl tempKey = rm.loadTemporaryKeyByRegistrationKey(key); if (tempKey != null) { XStream xml = XStreamHelper.createXStreamInstance(); @@ -223,12 +212,38 @@ public class ProfileFormController extends FormBasicController { // add the "about me" text field. groupContainer = FormLayoutContainer.createDefaultFormLayout("group.about", getTranslator()); groupContainer.setFormTitle(translate("form.group.about")); - this.formItems.put("group.about", groupContainer); formLayout.add(groupContainer); - - textAboutMe = uifactory.addRichTextElementForStringData("form.text", "form.text", this.conf.getTextAboutMe(), 10, -1, false, null, null, groupContainer, ureq.getUserSession(), getWindowControl()); + + HomePageConfig conf = hpcm.loadConfigFor(identityToModify.getName()); + textAboutMe = uifactory.addRichTextElementForStringData("form.text", "form.text", + conf.getTextAboutMe(), 10, -1, false, null, null, groupContainer, + ureq.getUserSession(), getWindowControl()); textAboutMe.setMaxLength(10000); - formItems.put("form.text", this.textAboutMe); + + //upload image + groupContainer = FormLayoutContainer.createDefaultFormLayout("portraitupload", getTranslator()); + groupContainer.setFormTitle(translate("ul.header")); + groupContainer.setFormContextHelp("org.olat.user","home-picture.html","chelp.home-picture.hover"); + formLayout.add(groupContainer); + + deletePortrait = uifactory.addFormLink("command.delete", groupContainer, Link.BUTTON); + + File portraitFile = dps.getBigPortrait(identityToModify.getName()); + // Init upload controller + Set<String> mimeTypes = new HashSet<String>(); + mimeTypes.add("image/gif"); + mimeTypes.add("image/jpg"); + mimeTypes.add("image/jpeg"); + mimeTypes.add("image/png"); + + portraitUpload = uifactory.addFileElement("ul.select", "ul.select", groupContainer); + portraitUpload.setMaxUploadSizeKB(10000, null, null); + portraitUpload.setPreview(ureq.getUserSession(), true); + portraitUpload.addActionListener(FormEvent.ONCHANGE); + if(portraitFile != null) { + portraitUpload.setInitialFile(portraitFile); + } + portraitUpload.limitToMimeType(mimeTypes, null, null); // Create submit and cancel buttons FormLayoutContainer buttonLayoutWrappper = FormLayoutContainer.createDefaultFormLayout("buttonLayoutWrappper", getTranslator()); @@ -237,10 +252,6 @@ public class ProfileFormController extends FormBasicController { buttonLayoutWrappper.add(buttonLayout); uifactory.addFormSubmitButton("save", buttonLayout); uifactory.addFormCancelButton("cancel", buttonLayout, ureq, getWindowControl()); - formItems.put("buttonLayout", buttonLayout); - - Set<String> userPropertyNames = formItems.keySet(); - ((VelocityContainer)this.flc.getComponent()).contextPut("userPropertyNames", userPropertyNames); } /** @@ -251,69 +262,46 @@ public class ProfileFormController extends FormBasicController { * visible fields). * @param identity The user's identity */ - public void updateFromFormData(final HomePageConfig config, final Identity identity) { - User user = identity.getUser(); + public void updateFromFormData() { + User user = identityToModify.getUser(); // For each user property... for (UserPropertyHandler userPropertyHandler : userPropertyHandlers) { - // ...get the value from the form field and store it into the user // property... FormItem formItem = formItems.get(userPropertyHandler.getName()); if(formItem.isEnabled()) { userPropertyHandler.updateUserFromFormItem(user, formItem); } - - // ...and store the "publish" flag for each property. - MultipleSelectionElement checkbox = publishCheckboxes.get("checkbox_" + userPropertyHandler.getName()); - if (checkbox != null) { - // null when not enabled for the org.olat.user.HomePageConfig usage - // identifier key - if (checkbox.getSelectedKeys().size() == 0) { - config.setEnabled(userPropertyHandler.getName(), false); - } else { - config.setEnabled(userPropertyHandler.getName(), true); - } - } } // Store the "about me" text. + HomePageConfig conf = hpcm.loadConfigFor(identityToModify.getName()); conf.setTextAboutMe(textAboutMe.getValue()); + hpcm.saveConfigTo(identityToModify.getName(), conf); } - - /** - * Take form data and set it in the user fields for the current subject - * - * @param id The identity to be updated (transient, does not do any db calls) - * @return the updated identity object - */ - public Identity updateIdentityFromFormData(Identity id) { - identity = id; - User user = identity.getUser(); - // update each user field + + public Identity updateIdentityFromFormData(Identity identity) { + identityToModify = identity; + User user = identityToModify.getUser(); for (UserPropertyHandler userPropertyHandler : userPropertyHandlers) { FormItem formItem = formItems.get(userPropertyHandler.getName()); if(formItem.isEnabled()) { userPropertyHandler.updateUserFromFormItem(user, formItem); } } - return identity; + return identityToModify; } - /* - * (non-Javadoc) - * - * @seeorg.olat.core.gui.components.form.flexible.impl.FormBasicController# - * validateFormLogic(org.olat.core.gui.UserRequest) - */ @Override protected boolean validateFormLogic(UserRequest ureq) { - boolean formOK = true; - User user = identity.getUser(); - for (UserPropertyHandler userPropertyHandler : this.userPropertyHandlers) { + boolean allOk = true; + formContext.put("username", identityToModify.getName()); + + User user = identityToModify.getUser(); + for (UserPropertyHandler userPropertyHandler : userPropertyHandlers) { FormItem formItem = formItems.get(userPropertyHandler.getName()); - if (!userPropertyHandler.isValid(user, formItem, formContext)) { - formOK = false; - } else { + if(formItem.isEnabled()) { formItem.clearError(); + allOk &= userPropertyHandler.isValid(user, formItem, formContext); } } @@ -321,15 +309,247 @@ public class ProfileFormController extends FormBasicController { String aboutMe = textAboutMe.getValue(); if(aboutMe.length() > 10000) { textAboutMe.setErrorKey("input.toolong", new String[] {"10000"}); - formOK = false; + allOk = false; } else { textAboutMe.clearError(); } } catch (Exception e) { textAboutMe.setErrorKey("input.toolong", new String[] {"10000"}); - formOK = false; + allOk = false; + } + return allOk & super.validateFormLogic(ureq); + } + + @Override + protected void formNOK(UserRequest ureq) { + fireEvent(ureq, Event.FAILED_EVENT); + } + + @Override + protected void formCancelled(UserRequest ureq) { + fireEvent(ureq, Event.CANCELLED_EVENT); + } + + @Override + protected void event(UserRequest ureq, Controller source, Event event) { + if (source == dialogCtr) { + dialogCtr.dispose(); + dialogCtr = null; + if (DialogBoxUIFactory.isYesEvent(event)) { + if (changedEmail != null) { + createChangeEmailWorkflow(ureq); + } + } + fireEvent(ureq, Event.FAILED_EVENT); + } + super.event(ureq, source, event); + } + + @Override + protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) { + if (source == portraitUpload) { + if (portraitUpload.isUploadSuccess()) { + deletePortrait.setVisible(true); + flc.setDirty(true); + } + } else if (source == deletePortrait) { + File img = dps.getBigPortrait(identityToModify.getName()); + if(portraitUpload.getUploadFile() != null) { + portraitUpload.reset(); + if(img == null) { + deletePortrait.setVisible(false); + } else { + deletePortrait.setVisible(true); + } + } else if(img != null) { + dps.deletePortrait(identityToModify); + deletePortrait.setVisible(false); + portraitUpload.setInitialFile(null); + } + flc.setDirty(true); + } + + super.formInnerEvent(ureq, source, event); + } + + @Override + protected void formOK(final UserRequest ureq) { + User user = identityToModify.getUser(); + // update each user field + for (UserPropertyHandler userPropertyHandler : userPropertyHandlers) { + FormItem formItem = formItems.get(userPropertyHandler.getName()); + if(formItem.isEnabled()) { + userPropertyHandler.updateUserFromFormItem(user, formItem); + } + } + + File uploadedImage = portraitUpload.getUploadFile(); + if(uploadedImage != null) { + dps.setPortrait(uploadedImage, identityToModify.getName()); + } + + // fire the appropriate event + fireEvent(ureq, Event.DONE_EVENT); + + // update the user profile data + CoordinatorManager.getInstance().getCoordinator().getSyncer().doInSync( + OresHelper.createOLATResourceableInstance(Identity.class, identityToModify.getKey()), new SyncerExecutor() { + @Override + public void execute() { + UserManager um = UserManager.getInstance(); + identityToModify = (Identity) DBFactory.getInstance().loadObject(identityToModify); + currentEmail = identityToModify.getUser().getProperty("email", null); + + identityToModify = updateIdentityFromFormData(identityToModify); + changedEmail = identityToModify.getUser().getProperty("email", null); + if (!currentEmail.equals(changedEmail)) { + // allow an admin to change email without verification workflow. usermanager is only permitted to do so, if set by config. + if ( !(ureq.getUserSession().getRoles().isOLATAdmin() + || (BaseSecurityModule.USERMANAGER_CAN_BYPASS_EMAILVERIFICATION && ureq.getUserSession().getRoles().isUserManager() ))) { + emailChanged = true; + // change email address to old address until it is verified + identityToModify.getUser().setProperty("email", currentEmail); + } else { + String key = identityToModify.getUser().getProperty("emchangeKey", null); + TemporaryKeyImpl tempKey = rm.loadTemporaryKeyByRegistrationKey(key); + if (tempKey != null) { + rm.deleteTemporaryKey(tempKey); + } + } + } + if (!um.updateUserFromIdentity(identityToModify)) { + getWindowControl().setInfo(translate("profile.unsuccessful")); + // reload user data from db + identityToModify = BaseSecurityManager.getInstance().loadIdentityByKey(identityToModify.getKey()); + } + + OLATResourceable modRes = OresHelper.createOLATResourceableInstance(Identity.class, identityToModify.getKey()); + CoordinatorManager.getInstance().getCoordinator().getEventBus() + .fireEventToListenersOf(new MultiUserEvent("changed"), modRes); + + if (!emailChanged) { + fireEvent(ureq, Event.FAILED_EVENT); + } + } + }); + + if (emailChanged) { + removeAsListenerAndDispose(dialogCtr); + + String changerEMail = ureq.getIdentity().getUser().getProperty("email", ureq.getLocale()); + String dialogText = ""; + if(changerEMail != null && changerEMail.length() > 0 && changerEMail.equals(currentEmail)) { + dialogText = translate("email.change.dialog.text"); + } else { + dialogText = translate("email.change.dialog.text.usermanager"); + } + dialogCtr = DialogBoxUIFactory.createYesNoDialog(ureq, getWindowControl(), translate("email.change.dialog.title"), dialogText); + listenTo(dialogCtr); + dialogCtr.activate(); + } + } + + private void createChangeEmailWorkflow(UserRequest ureq) { + // send email + changedEmail = changedEmail.trim(); + String body = null; + String subject = null; + // get remote address + String ip = ureq.getHttpReq().getRemoteAddr(); + String today = DateFormat.getDateInstance(DateFormat.LONG, ureq.getLocale()).format(new Date()); + // mailer configuration + String serverpath = Settings.getServerContextPathURI(); + String servername = ureq.getHttpReq().getServerName(); + + logDebug("this servername is " + servername + " and serverpath is " + serverpath, null); + // load or create temporary key + Map<String, String> mailMap = new HashMap<String, String>(); + mailMap.put("currentEMail", currentEmail); + mailMap.put("changedEMail", changedEmail); + + XStream xml = new XStream(); + String serMailMap = xml.toXML(mailMap); + + TemporaryKey tk = loadCleanTemporaryKey(serMailMap); + if (tk == null) { + tk = rm.createTemporaryKeyByEmail(serMailMap, ip, RegistrationManager.EMAIL_CHANGE); + } else { + rm.deleteTemporaryKeyWithId(tk.getRegistrationKey()); + tk = rm.createTemporaryKeyByEmail(serMailMap, ip, RegistrationManager.EMAIL_CHANGE); + } + + // create date, time string + Calendar cal = Calendar.getInstance(); + cal.setTime(tk.getCreationDate()); + cal.add(Calendar.DAY_OF_WEEK, ChangeEMailController.TIME_OUT); + String time = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, ureq.getLocale()).format(cal.getTime()); + // create body and subject for email + body = translate("email.change.body", new String[] { serverpath + "/dmz/emchange/index.html?key=" + tk.getRegistrationKey() + "&lang=" + ureq.getLocale().getLanguage(), time, currentEmail, changedEmail }) + + SEPARATOR + translate("email.change.wherefrom", new String[] { serverpath, today, ip }); + subject = translate("email.change.subject"); + // send email + try { + + MailBundle bundle = new MailBundle(); + bundle.setFrom(WebappHelper.getMailConfig("mailReplyTo")); + bundle.setTo(changedEmail); + bundle.setContent(subject, body); + + MailerResult result = mailManager.sendMessage(bundle); + boolean isMailSent = result.isSuccessful(); + if (isMailSent) { + tk.setMailSent(true); + // set key + User user = this.identityToModify.getUser(); + user.setProperty("emchangeKey", tk.getRegistrationKey()); + UserManager.getInstance().updateUser(user); + getWindowControl().setInfo(translate("email.sent")); + } else { + tk.setMailSent(false); + rm.deleteTemporaryKeyWithId(tk.getRegistrationKey()); + getWindowControl().setError(translate("email.notsent")); + } + } catch (Exception e) { + rm.deleteTemporaryKeyWithId(tk.getRegistrationKey()); + getWindowControl().setError(translate("email.notsent")); + } + } + + /** + * Load and clean temporary keys with action "EMAIL_CHANGE". + * @param serMailMap + * @return + */ + private TemporaryKey loadCleanTemporaryKey(String serMailMap) { + TemporaryKey tk = rm.loadTemporaryKeyByEmail(serMailMap); + if (tk == null) { + XStream xml = new XStream(); + @SuppressWarnings("unchecked") + Map<String, String> mails = (Map<String, String>) xml.fromXML(serMailMap); + String currentEMail = mails.get("currentEMail"); + List<TemporaryKey> tks = rm.loadTemporaryKeyByAction(RegistrationManager.EMAIL_CHANGE); + if (tks != null) { + synchronized (tks) { + tks = rm.loadTemporaryKeyByAction(RegistrationManager.EMAIL_CHANGE); + int countCurrentEMail = 0; + for (TemporaryKey temporaryKey : tks) { + @SuppressWarnings("unchecked") + Map<String, String> tkMails = (Map<String, String>) xml.fromXML(temporaryKey.getEmailAddress()); + if (tkMails.get("currentEMail").equals(currentEMail)) { + if (countCurrentEMail > 0) { + // clean + rm.deleteTemporaryKeyWithId(temporaryKey.getRegistrationKey()); + } else { + // load + tk = temporaryKey; + } + countCurrentEMail++; + } + } + } + } } - return formOK && super.validateFormLogic(ureq); + return tk; } /** diff --git a/src/main/java/org/olat/user/_content/combinedform.html b/src/main/java/org/olat/user/_content/combinedform.html deleted file mode 100644 index ae1533d528e07c460408688f7dbcbf6011409309..0000000000000000000000000000000000000000 --- a/src/main/java/org/olat/user/_content/combinedform.html +++ /dev/null @@ -1,30 +0,0 @@ -<div class="o_form form-horizontal" role="form"> -#foreach ($item in $formitemnames) - $r.render(${item}) -#* - #if ($userPropertyNames.contains($item)) - #if ($f.isVisible($item)) - <div class="form-group $f.getElementCssClass($item) #if($f.hasError($item)) has-error #end"> - #if ($f.hasLabel($item)) - $r.render("${item}_LABEL", "$f.getItemId($item)", "$f.isMandatory($item)") - #end - #if ($r.available("checkbox_${item}")) - $r.render("checkbox_${item}") - #else - $r.render(${item}) - #if($f.hasExample($item)) - <p class="help-block"> - $r.render("${item}_EXAMPLE") - </p> - #end - #if($f.hasError($item)) - <span class="o_icon o_icon_error form-control-feedback"></span> - $r.render("${item}_ERROR") - #end - #end - </div> - #end - #end -*# -#end -</div> diff --git a/src/main/java/org/olat/user/_content/homepage.html b/src/main/java/org/olat/user/_content/homepage.html index 6ea5c3a5ce2c85865e879976ef136ff00abfc4e1..f70c71d46f469cf5b3ce088bd7678344b3287bea 100644 --- a/src/main/java/org/olat/user/_content/homepage.html +++ b/src/main/java/org/olat/user/_content/homepage.html @@ -1,21 +1,7 @@ -<h2> - $r.contextHelpWithWrapper("org.olat.user","home-vcard.html","help.hover.vcard") - $r.translate("title.homepage") +<p class="o_note">$r.translate("form.description")</p> +$r.render("segments") +<div class="o_segments_content"> + $r.render("segmentCmp") +</div> -</h2> -<p class="o_note"> - $r.translate("form.description") -</p> -<p> - $r.render("command.preview") -</p> - -$r.render("homepageform") -<fieldset> - <legend> - $r.contextHelpWithWrapper("org.olat.user","home-picture.html","chelp.home-picture.hover") - $r.translate("ul.header") - </legend> - $r.render("c") -</fieldset> \ No newline at end of file diff --git a/src/main/java/org/olat/user/_content/homepage_preview.html b/src/main/java/org/olat/user/_content/homepage_preview.html new file mode 100644 index 0000000000000000000000000000000000000000..6f5107451dac5099f9cbc0bec9b425e6bb15e078 --- /dev/null +++ b/src/main/java/org/olat/user/_content/homepage_preview.html @@ -0,0 +1,10 @@ +<fieldset> + <legend>$!off_title</legend> +#foreach ($item in $formitemnames) + #if ($f.isVisible($item)) + $r.render(${item}) + #end +#end +</fieldset> + + diff --git a/src/main/java/org/olat/user/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/user/_i18n/LocalStrings_de.properties index 75f7b71c53df7b09ee0acfcaa0d03b0c1c7a5b18..f1e16e1c42ce80a5abaf15e9b73a839340ba5f16 100644 --- a/src/main/java/org/olat/user/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/user/_i18n/LocalStrings_de.properties @@ -85,6 +85,7 @@ chelp.usertools1=Benutzerwerkzeug Hilfe command.closehp=Vorschau schliessen command.delete=L\u00F6schen command.preview=Vorschau anzeigen +tab.preview=Vorschau error.no.props.found=Es wurden keine Properties f\u00FCr diesen Benutzer gefunden form.checkPassword=Das Passwort muss mindestens 4 Zeichen haben. Verwenden Sie dabei sowohl Ziffern als auch Buchstaben. error.password.empty=Geben Sie Ihr bisheriges Passwort an