Skip to content
Snippets Groups Projects
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
RegistrationController.java 20.33 KiB
/**
* 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.registration;

import java.text.DateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import org.olat.basesecurity.AuthHelper;
import org.olat.basesecurity.BaseSecurityManager;
import org.olat.basesecurity.BaseSecurityModule;
import org.olat.core.CoreSpringFactory;
import org.olat.core.commons.chiefcontrollers.LanguageChangedEvent;
import org.olat.core.commons.fullWebApp.LayoutMain3ColsController;
import org.olat.core.dispatcher.DispatcherModule;
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.link.Link;
import org.olat.core.gui.components.link.LinkFactory;
import org.olat.core.gui.components.panel.Panel;
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.dtabs.Activateable2;
import org.olat.core.gui.control.generic.messages.MessageController;
import org.olat.core.gui.control.generic.messages.MessageUIFactory;
import org.olat.core.gui.control.generic.wizard.WizardInfoController;
import org.olat.core.gui.media.RedirectMediaResource;
import org.olat.core.helpers.Settings;
import org.olat.core.id.Identity;
import org.olat.core.id.Preferences;
import org.olat.core.id.User;
import org.olat.core.id.context.ContextEntry;
import org.olat.core.id.context.StateEntry;
import org.olat.core.util.StringHelper;
import org.olat.core.util.Util;
import org.olat.core.util.WebappHelper;
import org.olat.core.util.i18n.I18nManager;
import org.olat.core.util.i18n.I18nModule;
import org.olat.core.util.mail.MailBundle;
import org.olat.core.util.mail.MailManager;
import org.olat.core.util.mail.MailerResult;
import org.olat.dispatcher.LocaleNegotiator;
import org.olat.user.UserManager;
import org.olat.user.UserPropertiesConfig;
import org.olat.user.propertyhandlers.UserPropertyHandler;
import org.springframework.beans.factory.annotation.Autowired;

/**
 * Description:<br>
 * Controls the registration workflow.
 * 
 * <P>
 * @author Sabina Jeger
 */
public class RegistrationController extends BasicController implements Activateable2 {

	private static final String SEPARATOR = "____________________________________________________________________\n";

	private VelocityContainer myContent;	
	private Panel regarea;
	private Link loginButton;
	private WizardInfoController wizInfoController;
	private DisclaimerController disclaimerController;
	private EmailSendingForm emailSendForm;
	private RegistrationForm2 registrationForm;
	private LanguageChooserController langChooserController;
	private String uniqueRegistrationKey;
	private TemporaryKey tempKey;
	
	@Autowired
	private I18nManager i18nManager;
	@Autowired
	private UserManager userManager;
	@Autowired
	private MailManager mailManager;
	@Autowired
	private RegistrationModule registrationModule;
	@Autowired
	private RegistrationManager registrationManager;

	/**
	 * Controller implementing registration work flow.
	 * @param ureq
	 * @param wControl
	 */
	public RegistrationController(UserRequest ureq, WindowControl wControl) {
		super(ureq, wControl);		
		if (!registrationModule.isSelfRegistrationEnabled()) {
			String contact = WebappHelper.getMailConfig("mailSupport");
			String text = translate("reg.error.disabled.body", new String[]{ contact });
			MessageController msg = MessageUIFactory.createWarnMessage(ureq, getWindowControl(), null, text);
			LayoutMain3ColsController layoutCtr = new LayoutMain3ColsController(ureq, getWindowControl(), null, msg.getInitialComponent(), null);
			listenTo(layoutCtr);
			putInitialPanel(layoutCtr.getInitialComponent());
			return;
		}
		// override language when not the same as in ureq and add fallback to
		// property handler translator for user properties
		String lang = ureq.getParameter("language");
		if (lang == null) {
			// support for legacy lang parameter
			lang = ureq.getParameter("lang");
		}
		if (lang != null && ! lang.equals(i18nManager.getLocaleKey(getLocale()))) {
			Locale loc = i18nManager.getLocaleOrDefault(lang);
			ureq.getUserSession().setLocale(loc);
			setLocale(loc, true);
			setTranslator(userManager.getPropertyHandlerTranslator(Util.createPackageTranslator(this.getClass(), loc)));			
		}	else {
			// set fallback only
			setTranslator(userManager.getPropertyHandlerTranslator(getTranslator()));			
		}
		
		//construct content
		myContent = createVelocityContainer("reg");
		wizInfoController = new WizardInfoController(ureq, 5);
		listenTo(wizInfoController);
		myContent.put("regwizard", wizInfoController.getInitialComponent());
		regarea = new Panel("regarea");
		myContent.put("regarea", regarea);
		uniqueRegistrationKey = ureq.getHttpReq().getParameter("key");
		if (uniqueRegistrationKey == null || uniqueRegistrationKey.equals("")) {
			// no temporary key is given, we assume step 1. If this is the case, we
			// render in a modal dialog, no need to add the 3cols layout controller
			// wrapper
			//fxdiff FXOLAT-113: business path in DMZ
			if(I18nModule.getEnabledLanguageKeys().size() == 1) {
				wizInfoController.setCurStep(2);
				createEmailForm(ureq);
			} else {
				createLanguageForm(ureq, wControl);
			}
			putInitialPanel(myContent);
		} else {
			// we check if given key is a valid temporary key
			tempKey = registrationManager.loadTemporaryKeyByRegistrationKey(uniqueRegistrationKey);
			// if key is not valid we redirect to first page
			if (tempKey == null) {
				// error, there should be an entry
				showError("regkey.missingentry");
				//fxdiff FXOLAT-113: business path in DMZ
				if(I18nModule.getEnabledLanguageKeys().size() == 1) {
					wizInfoController.setCurStep(2);
					createEmailForm(ureq);
				} else {
					createLanguageForm(ureq, wControl);
				}
			} else {
				wizInfoController.setCurStep(3);
				myContent.contextPut("pwdhelp", translate("pwdhelp"));
				myContent.contextPut("loginhelp", translate("loginhelp"));
				myContent.contextPut("text", translate("step3.reg.text"));
				myContent.contextPut("email", tempKey.getEmailAddress());

				Map<String,String> userAttrs = new HashMap<String,String>();
				userAttrs.put("email", tempKey.getEmailAddress());
				
				if(registrationModule.getUsernamePresetBean() != null) {
					UserNameCreationInterceptor interceptor = registrationModule.getUsernamePresetBean();
					String proposedUsername = interceptor.getUsernameFor(userAttrs);
					if(proposedUsername == null) {
						if(interceptor.allowChangeOfUsername()) {
							createRegForm2(ureq, null, false, false);
						} else {
							myContent = setErrorPage("reg.error.no_username", wControl);
						}
					} else {
						Identity identity = BaseSecurityManager.getInstance().findIdentityByName(proposedUsername);
						if(identity != null) {
							if(interceptor.allowChangeOfUsername()) {
								createRegForm2(ureq, proposedUsername, true, false);
							} else {
								myContent = setErrorPage("reg.error.user_in_use", wControl);
							}
						} else if (interceptor.allowChangeOfUsername()) {
							createRegForm2(ureq, proposedUsername, false, false);
						} else {
							createRegForm2(ureq, proposedUsername, false, true);
						}
					}
				} else {
					createRegForm2(ureq, null, false, false);
				}
			}
			// load view in layout
			LayoutMain3ColsController layoutCtr = new LayoutMain3ColsController(ureq, getWindowControl(), null, myContent, null);
			listenTo(layoutCtr);
			putInitialPanel(layoutCtr.getInitialComponent());
		}		
	}
	
	public String getWizardTitle() {
		return translate("step1.reg.title");
	}
	
	private VelocityContainer setErrorPage(String errorKey, WindowControl wControl) {
		String error = getTranslator().translate(errorKey);
		wControl.setError(error);
		VelocityContainer errorContainer = createVelocityContainer("error");
		errorContainer.contextPut("errorMsg", error);
		return errorContainer;
	}
	
	private void createRegForm2(UserRequest ureq, String proposedUsername, boolean userInUse, boolean usernameReadonly) {
		registrationForm = new RegistrationForm2(ureq, getWindowControl(), I18nManager.getInstance().getLocaleKey(getLocale()), proposedUsername, userInUse, usernameReadonly);
		listenTo(registrationForm);
		regarea.setContent(registrationForm.getInitialComponent());
	}
	
	private void createLanguageForm(UserRequest ureq, WindowControl wControl) {
		removeAsListenerAndDispose(langChooserController);
		langChooserController = new LanguageChooserController(ureq, wControl, true);
		listenTo(langChooserController);
		myContent.contextPut("text", translate("select.language.description"));
		regarea.setContent(langChooserController.getInitialComponent());
	}

	/**
	 * just needed for creating EmailForm
	 */
	private void createEmailForm(UserRequest ureq) {
		removeAsListenerAndDispose(emailSendForm);
		emailSendForm = new EmailSendingForm(ureq, getWindowControl());
		listenTo(emailSendForm);
		
		myContent.contextPut("text", translate("step1.reg.text"));
		regarea.setContent(emailSendForm.getInitialComponent());
	}

	@Override
	public void activate(UserRequest ureq, List<ContextEntry> entries, StateEntry state) {
		if(entries == null || entries.isEmpty()) return;
	}

	@Override
	public void event(UserRequest ureq, Component source, Event event) {
		if(source == loginButton) {
			Identity persistedIdentity = (Identity)loginButton.getUserObject();
			doLogin(ureq, persistedIdentity);
		}
	}

	/**
	 * @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) {
		if (source == emailSendForm) {
			if (event == Event.DONE_EVENT) { // form
				// validation
				// was ok
				wizInfoController.setCurStep(2);
				// Email requested for tempkey
				//save the fields somewhere
				String email = emailSendForm.getEmailAddress();
				myContent.contextPut("email", email);
				myContent.contextPut("text", translate("step2.reg.text", email));
				//ef.setVisible(false);
				regarea.setVisible(false);
				// look for user in "Person" and "user" tables
				boolean foundUser = UserManager.getInstance().userExist(email);
				// get remote address
				String ip = ureq.getHttpReq().getRemoteAddr();
				String serverpath = Settings.getServerContextPathURI();
				String today = DateFormat.getDateInstance(DateFormat.LONG, ureq.getLocale()).format(new Date());
				String[] whereFromAttrs = new String[]{
					serverpath, today, ip
				};

				boolean isMailSent = false;
				if (!foundUser) {
					TemporaryKey tk = registrationManager.loadTemporaryKeyByEmail(email);
					if (tk == null) tk = registrationManager.createTemporaryKeyByEmail(email, ip, RegistrationManager.REGISTRATION);
					myContent.contextPut("regKey", tk.getRegistrationKey());
					
					String link = serverpath + "/dmz/registration/index.html?key=" + tk.getRegistrationKey() + "&language=" + i18nManager.getLocaleKey(ureq.getLocale());
					String[] bodyAttrs = new String[]{
						serverpath,										//0
						tk.getRegistrationKey(),						//1
						i18nManager.getLocaleKey(ureq.getLocale()),		//2
						"<a href=\"" + link + "\">" + link + "</a>"		//3
					};
					
					String body = translate("reg.body", bodyAttrs);
					boolean htmlBody = StringHelper.isHtml(body);
					if(!htmlBody) {
						body += SEPARATOR + translate("reg.wherefrom", whereFromAttrs);
					}
					
					try {
						MailBundle bundle = new MailBundle();
						bundle.setTo(email);
						bundle.setContent(translate("reg.subject"), body);
						MailerResult result = mailManager.sendExternMessage(bundle, null, htmlBody);
						if (result.isSuccessful()) {
							isMailSent = true;
						}
					} catch (Exception e) {
						// nothing to do, emailSent flag is false, errors will be reported to user
					}
				} else {
					// a user exists, this is an error in the registration page
					// send email
					Identity identity = UserManager.getInstance().findIdentityByEmail(email);
					String body = translate("login.body", identity.getName()) + SEPARATOR + translate("reg.wherefrom", whereFromAttrs);
					try {
						MailBundle bundle = new MailBundle();
						bundle.setTo(email);
						bundle.setContent(translate("login.subject"), body);
						MailerResult result = mailManager.sendExternMessage(bundle, null, true);
						if (result.isSuccessful()) {
							isMailSent = true;
						}
					} catch (Exception e) {
						// nothing to do, emailSent flag is false, errors will be reported to user
					}
				}
				if (isMailSent) {
					showInfo("email.sent");
				} else {
					showError("email.notsent");
				}
			} else if (event == Event.CANCELLED_EVENT) {
				fireEvent(ureq, Event.CANCELLED_EVENT);
			}
		} else if (source == langChooserController) {
			if (event == Event.DONE_EVENT) {
				wizInfoController.setCurStep(2);
				createEmailForm(ureq);
				ureq.getUserSession().removeEntry(LocaleNegotiator.NEGOTIATED_LOCALE);
			} else if (event == Event.CANCELLED_EVENT) {
				ureq.getDispatchResult().setResultingMediaResource(new RedirectMediaResource(Settings.getServerContextPathURI()));
			} else if (event instanceof LanguageChangedEvent) {
				LanguageChangedEvent lcev = (LanguageChangedEvent)event;
				setLocale(lcev.getNewLocale(), true);
				myContent.contextPut("text", translate("select.language.description"));
			}
		} else if (source == registrationForm) {
			// Userdata entered
			if (event == Event.DONE_EVENT) {
				String lang = registrationForm.getLangKey();
				// change language if different then current language
				if (! lang.equals(I18nManager.getInstance().getLocaleKey(ureq.getLocale()))) {
					Locale loc = I18nManager.getInstance().getLocaleOrDefault(lang);
					ureq.getUserSession().setLocale(loc);
					getTranslator().setLocale(loc);					
				}

				
				wizInfoController.setCurStep(4);
				myContent.contextPut("pwdhelp", "");
				myContent.contextPut("loginhelp", "");
				myContent.contextPut("text", translate("step4.reg.text"));
				
				removeAsListenerAndDispose(disclaimerController);
				disclaimerController = new DisclaimerController(ureq, getWindowControl());
				listenTo(disclaimerController);
				
				regarea.setContent(disclaimerController.getInitialComponent());
			} else if (event == Event.CANCELLED_EVENT) {
				ureq.getDispatchResult().setResultingMediaResource(new RedirectMediaResource(Settings.getServerContextPathURI()));
			}
		} else if (source == disclaimerController) {
			if (event == Event.DONE_EVENT) {
				// finalize the registration by creating the user
				Identity persitedIdentity = createNewUserAfterRegistration();
				// display step5
				displayFinalStep(persitedIdentity);
			} else if (event == Event.CANCELLED_EVENT) {
				ureq.getDispatchResult().setResultingMediaResource(new RedirectMediaResource(Settings.getServerContextPathURI()));
			}
		}

	}

	/**
	 * OO-92
	 * 
	 * displays the final step of the registration process. (step5)<br />
	 * see also _content/finish.html
	 * 
	 * @param user
	 *            The newly created User from which to display information
	 * 
	 */
	private void displayFinalStep(Identity persitedIdentity){
		// set wizard step to 5
		wizInfoController.setCurStep(5);
		
		// hide the text we don't need anymore 
		myContent.contextPut("pwdhelp", "");
		myContent.contextPut("loginhelp", "");
		myContent.contextPut("text", "");
		
		// show last screen
		VelocityContainer finishVC = createVelocityContainer("finish");
		
		List<UserPropertyHandler> userPropertyHandlers = UserManager.getInstance().getUserPropertyHandlersFor(RegistrationForm2.USERPROPERTIES_FORM_IDENTIFIER, false);
		finishVC.contextPut("userPropertyHandlers", userPropertyHandlers);
		finishVC.contextPut("user", persitedIdentity.getUser());
		finishVC.contextPut("locale", getLocale());
		finishVC.contextPut("username", registrationForm.getLogin());
		finishVC.contextPut("text", getTranslator().translate("step5.reg.text", new String[]{ registrationForm.getLogin() }));
		loginButton = LinkFactory.createButton("form.login", finishVC, this);
		loginButton.setCustomEnabledLinkCSS("btn btn-primary");
		loginButton.setUserObject(persitedIdentity);
		finishVC.put("loginhref", loginButton);
		
		regarea.setContent(finishVC);
	}
	
	/**
	 * OO-92
	 * this will finally create the user, set all it's userproperties
	 * 
	 * @return User the newly created, persisted User Object
	 */
	private Identity createNewUserAfterRegistration() {
		// create user with mandatory fields from registration-form
		UserManager um = UserManager.getInstance();
		User volatileUser = um.createUser(registrationForm.getFirstName(), registrationForm.getLastName(), tempKey.getEmailAddress());
		// set user configured language
		Preferences preferences = volatileUser.getPreferences();

		preferences.setLanguage(registrationForm.getLangKey());
		volatileUser.setPreferences(preferences);
		// create an identity with the given username / pwd and the user object
		String login = registrationForm.getLogin();
		String pwd = registrationForm.getPassword();
		Identity persistedIdentity = registrationManager.createNewUserAndIdentityFromTemporaryKey(login, pwd, volatileUser, tempKey);
		if (persistedIdentity == null) {
			showError("user.notregistered");
			return null;
		} else {
			// update other user properties from form
			List<UserPropertyHandler> userPropertyHandlers = um.getUserPropertyHandlersFor(RegistrationForm2.USERPROPERTIES_FORM_IDENTIFIER, false);
			User persistedUser = persistedIdentity.getUser();
			
			//add eventually static value
			UserPropertiesConfig userPropertiesConfig = CoreSpringFactory.getImpl(UserPropertiesConfig.class);
			if(registrationModule.isStaticPropertyMappingEnabled()) {
				String propertyName = registrationModule.getStaticPropertyMappingName();
				String propertyValue = registrationModule.getStaticPropertyMappingValue();
				if(StringHelper.containsNonWhitespace(propertyName)
						&& StringHelper.containsNonWhitespace(propertyValue)
						&& userPropertiesConfig.getPropertyHandler(propertyName) != null) {
					try {
						persistedUser.setProperty(propertyName, propertyValue);
					} catch (Exception e) {
						logError("Cannot set the static property value", e);
					}
				}
			}

			for (UserPropertyHandler userPropertyHandler : userPropertyHandlers) {
				FormItem fi = registrationForm.getPropFormItem(userPropertyHandler.getName());
				userPropertyHandler.updateUserFromFormItem(persistedUser, fi);
			}
			// persist changes in db
			um.updateUserFromIdentity(persistedIdentity);
			// send notification mail to sys admin
			String notiEmail = CoreSpringFactory.getImpl(RegistrationModule.class).getRegistrationNotificationEmail();
			if (notiEmail != null) {
				registrationManager.sendNewUserNotificationMessage(notiEmail, persistedIdentity);
			}

			// tell system that this user did accept the disclaimer
			registrationManager.setHasConfirmedDislaimer(persistedIdentity);
			return persistedIdentity;
		}
	}
	
	private void doLogin(UserRequest ureq, Identity persistedIdentity) {
		int loginStatus = AuthHelper.doLogin(persistedIdentity, BaseSecurityModule.getDefaultAuthProviderIdentifier(), ureq);
		if (loginStatus == AuthHelper.LOGIN_OK) {
			//youppi
		} else if (loginStatus == AuthHelper.LOGIN_NOTAVAILABLE){
			DispatcherModule.redirectToDefaultDispatcher(ureq.getHttpResp());
		} else {
			getWindowControl().setError(translate("login.error", WebappHelper.getMailConfig("mailReplyTo")));
		}
	}

	protected void doDispose() {
		//
	}

}