From 9d1a204b3967b2871ee898e005117f7b667343ad Mon Sep 17 00:00:00 2001
From: srosse <stephane.rosse@frentix.com>
Date: Fri, 14 Dec 2018 15:44:36 +0100
Subject: [PATCH] OO-3718: configurable addition form in the registration
 process

---
 .../RegistrationAdditionalForm.java           | 128 ++++++++++++++++++
 .../registration/RegistrationController.java  |  97 +++++++++----
 .../olat/registration/RegistrationForm2.java  |  37 +++--
 .../olat/registration/_content/finish.html    |   2 +-
 .../_i18n/LocalStrings_de.properties          |   2 +
 .../_i18n/LocalStrings_en.properties          |   2 +
 .../_spring/userPropertiesContext.xml         |  14 ++
 7 files changed, 237 insertions(+), 45 deletions(-)
 create mode 100644 src/main/java/org/olat/registration/RegistrationAdditionalForm.java

diff --git a/src/main/java/org/olat/registration/RegistrationAdditionalForm.java b/src/main/java/org/olat/registration/RegistrationAdditionalForm.java
new file mode 100644
index 00000000000..e59ab71f138
--- /dev/null
+++ b/src/main/java/org/olat/registration/RegistrationAdditionalForm.java
@@ -0,0 +1,128 @@
+/**
+ * <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.registration;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+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.impl.FormBasicController;
+import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer;
+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.translator.Translator;
+import org.olat.core.util.Util;
+import org.olat.user.ChangePasswordForm;
+import org.olat.user.UserManager;
+import org.olat.user.propertyhandlers.UserPropertyHandler;
+import org.springframework.beans.factory.annotation.Autowired;
+
+/**
+ * 
+ * Initial date: 14 déc. 2018<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class RegistrationAdditionalForm extends FormBasicController {
+	public static final String USERPROPERTIES_FORM_IDENTIFIER = RegistrationAdditionalForm.class.getCanonicalName();
+	
+	private final Map<String,FormItem> propFormItems = new HashMap<>();
+	private final List<UserPropertyHandler> userPropertyHandlers;
+
+	@Autowired
+	private UserManager userManager;
+	
+	/**
+	 * @param name
+	 * @param languageKey
+	 */
+	public RegistrationAdditionalForm(UserRequest ureq, WindowControl wControl) {
+		super(ureq, wControl, null, Util.createPackageTranslator(ChangePasswordForm.class, ureq.getLocale()));
+		userPropertyHandlers = userManager.getUserPropertyHandlersFor(USERPROPERTIES_FORM_IDENTIFIER, false);
+		initForm(ureq);
+	}
+	
+	protected List<UserPropertyHandler> getUserProperties() {
+		return userPropertyHandlers;
+	}
+
+	protected FormItem getPropFormItem(String k) {
+		return propFormItems.get(k);
+	}
+	/**
+	 * Initialize the form
+	 */
+
+	@Override
+	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
+		setFormTitle("step.add.reg.title");
+
+		Translator tr = Util.createPackageTranslator(UserPropertyHandler.class,getLocale(), getTranslator());
+		
+		// Add all available user fields to this form
+		for (UserPropertyHandler userPropertyHandler : userPropertyHandlers) {
+			if (userPropertyHandler == null) continue;
+			
+			FormItem fi = userPropertyHandler.addFormItem(getLocale(), null, USERPROPERTIES_FORM_IDENTIFIER, false, formLayout);
+			fi.setTranslator(tr);
+			propFormItems.put(userPropertyHandler.getName(), fi);
+		}
+
+		// Button layout
+		FormLayoutContainer buttonLayout = FormLayoutContainer.createButtonLayout("button_layout", getTranslator());
+		formLayout.add(buttonLayout);
+		uifactory.addFormCancelButton("cancel", buttonLayout, ureq, getWindowControl());
+		uifactory.addFormSubmitButton("submit.speichernUndweiter", buttonLayout);	
+	}
+
+	@Override
+	protected boolean validateFormLogic (UserRequest ureq) {
+		boolean allOk = super.validateFormLogic(ureq);
+		
+		// validate each user field
+		for (UserPropertyHandler userPropertyHandler : userPropertyHandlers) {
+			FormItem fi = propFormItems.get(userPropertyHandler.getName());
+			if (!userPropertyHandler.isValid(null, fi, null)) {
+				allOk &= false;
+			}
+		}
+
+		return allOk;
+	}
+	
+	@Override
+	protected void formOK(UserRequest ureq) {
+		fireEvent (ureq, Event.DONE_EVENT);
+	}
+	
+	@Override
+	protected void formCancelled(UserRequest ureq) {
+		fireEvent(ureq, Event.CANCELLED_EVENT);
+	}
+
+	@Override
+	protected void doDispose() {
+		//
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/org/olat/registration/RegistrationController.java b/src/main/java/org/olat/registration/RegistrationController.java
index 0c05a02072a..15ea45a05ce 100644
--- a/src/main/java/org/olat/registration/RegistrationController.java
+++ b/src/main/java/org/olat/registration/RegistrationController.java
@@ -26,6 +26,7 @@
 package org.olat.registration;
 
 import java.text.DateFormat;
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Date;
 import java.util.HashMap;
@@ -97,10 +98,13 @@ public class RegistrationController extends BasicController implements Activatea
 	private DisclaimerController disclaimerController;
 	private EmailSendingForm emailSendForm;
 	private RegistrationForm2 registrationForm;
+	private RegistrationAdditionalForm registrationAdditionalForm;
 	private LanguageChooserController langChooserController;
 	
 	private TemporaryKey tempKey;
 	private String uniqueRegistrationKey;
+	private final int numOfSteps;
+	private final boolean additionalRegistrationForm;
 	
 	@Autowired
 	private I18nModule i18nModule;
@@ -133,6 +137,8 @@ public class RegistrationController extends BasicController implements Activatea
 			LayoutMain3ColsController layoutCtr = new LayoutMain3ColsController(ureq, getWindowControl(), null, msg.getInitialComponent(), null);
 			listenTo(layoutCtr);
 			putInitialPanel(layoutCtr.getInitialComponent());
+			numOfSteps = 0;
+			additionalRegistrationForm = false;
 			return;
 		}
 		// override language when not the same as in ureq and add fallback to
@@ -152,9 +158,13 @@ public class RegistrationController extends BasicController implements Activatea
 			setTranslator(userManager.getPropertyHandlerTranslator(getTranslator()));			
 		}
 		
+		additionalRegistrationForm = !userManager
+				.getUserPropertyHandlersFor(RegistrationAdditionalForm.USERPROPERTIES_FORM_IDENTIFIER, false).isEmpty();
+		numOfSteps = additionalRegistrationForm ? 6 : 5;
+		
 		//construct content
 		myContent = createVelocityContainer("reg");
-		wizInfoController = new WizardInfoController(ureq, 5);
+		wizInfoController = new WizardInfoController(ureq, numOfSteps);
 		listenTo(wizInfoController);
 		myContent.put("regwizard", wizInfoController.getInitialComponent());
 		regarea = new Panel("regarea");
@@ -175,7 +185,7 @@ public class RegistrationController extends BasicController implements Activatea
 				showError("regkey.missingentry");
 				displayLanguageChooserStep(ureq);
 			} else {
-				displayRegistrationForm2(ureq);
+				displayRegistrationForm(ureq);
 			}
 			// load view in layout
 			LayoutMain3ColsController layoutCtr = new LayoutMain3ColsController(ureq, getWindowControl(), null, myContent, null);
@@ -196,12 +206,6 @@ public class RegistrationController extends BasicController implements Activatea
 		return errorContainer;
 	}
 	
-	private void createRegForm2(UserRequest ureq, String proposedUsername, boolean userInUse, boolean usernameReadonly) {
-		registrationForm = new RegistrationForm2(ureq, getWindowControl(), i18nModule.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);
@@ -225,12 +229,12 @@ public class RegistrationController extends BasicController implements Activatea
 
 	@Override
 	public void event(UserRequest ureq, Controller source, Event event) {
-		if (source == langChooserController) {
+		if (event == Event.CANCELLED_EVENT) {
+			cancel(ureq);
+		} else if (source == langChooserController) {
 			if (event == Event.DONE_EVENT) {
 				displayDisclaimer(ureq);
 				ureq.getUserSession().removeEntry(LocaleNegotiator.NEGOTIATED_LOCALE);
-			} else if (event == Event.CANCELLED_EVENT) {
-				cancel(ureq);
 			} else if (event instanceof LanguageChangedEvent) {
 				LanguageChangedEvent lcev = (LanguageChangedEvent)event;
 				setLocale(lcev.getNewLocale(), true);
@@ -240,8 +244,6 @@ public class RegistrationController extends BasicController implements Activatea
 			if (event == Event.DONE_EVENT) {
 				// finalize the registration by creating the user
 				displayEmailForm(ureq);
-			} else if (event == Event.CANCELLED_EVENT) {
-				cancel(ureq);
 			}
 		} else if (source == emailSendForm) {
 			if (event == Event.DONE_EVENT) { // form
@@ -251,11 +253,22 @@ public class RegistrationController extends BasicController implements Activatea
 				} else {
 					showError("email.notsent");
 				}
-			} else if (event == Event.CANCELLED_EVENT) {
-				fireEvent(ureq, Event.CANCELLED_EVENT);
 			}
 		}  else if (source == registrationForm) {
 			// Userdata entered
+			if (event == Event.DONE_EVENT) {
+				if(additionalRegistrationForm) {
+					displayRegistrationAdditionalForm(ureq);
+				} else {
+					Identity persitedIdentity = createNewUserAfterRegistration();
+					if(persitedIdentity == null) {
+						cancel(ureq);
+					} else {
+						displayFinalStep(persitedIdentity);
+					}
+				}
+			}
+		} else if(source == registrationAdditionalForm) {
 			if (event == Event.DONE_EVENT) {
 				Identity persitedIdentity = createNewUserAfterRegistration();
 				if(persitedIdentity == null) {
@@ -263,10 +276,8 @@ public class RegistrationController extends BasicController implements Activatea
 				} else {
 					displayFinalStep(persitedIdentity);
 				}
-			} else if (event == Event.CANCELLED_EVENT) {
-				cancel(ureq);
 			}
-		} 
+		}
 	}
 	
 	private void cancel(UserRequest ureq) {
@@ -396,7 +407,7 @@ public class RegistrationController extends BasicController implements Activatea
 		return isMailSent;
 	}
 	
-	private void displayRegistrationForm2(UserRequest ureq) {
+	private void displayRegistrationForm(UserRequest ureq) {
 		wizInfoController.setCurStep(4);
 		myContent.contextPut("pwdhelp", translate("pwdhelp"));
 		myContent.contextPut("loginhelp", translate("loginhelp"));
@@ -431,6 +442,27 @@ public class RegistrationController extends BasicController implements Activatea
 			createRegForm2(ureq, null, false, false);
 		}
 	}
+	
+	private void createRegForm2(UserRequest ureq, String proposedUsername, boolean userInUse, boolean usernameReadonly) {
+		registrationForm = new RegistrationForm2(ureq, getWindowControl(), i18nModule.getLocaleKey(getLocale()), proposedUsername, userInUse, usernameReadonly);
+		listenTo(registrationForm);
+		regarea.setContent(registrationForm.getInitialComponent());
+	}
+	
+	private void displayRegistrationAdditionalForm(UserRequest ureq) {
+		wizInfoController.setCurStep(5);
+		myContent.contextPut("pwdhelp", "");
+		myContent.contextPut("loginhelp", "");
+		myContent.contextPut("text", translate("step.add.reg.text"));
+		myContent.contextPut("email", tempKey.getEmailAddress());
+
+		Map<String,String> userAttrs = new HashMap<>();
+		userAttrs.put("email", tempKey.getEmailAddress());
+		
+		registrationAdditionalForm = new RegistrationAdditionalForm(ureq, getWindowControl());
+		listenTo(registrationAdditionalForm);
+		regarea.setContent(registrationAdditionalForm.getInitialComponent());
+	}
 
 	/**
 	 * OO-92
@@ -444,18 +476,22 @@ public class RegistrationController extends BasicController implements Activatea
 	 */
 	private void displayFinalStep(Identity persitedIdentity){
 		// set wizard step to 5
-		wizInfoController.setCurStep(5);
+		wizInfoController.setCurStep(numOfSteps);
 		
 		// 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.getUserPropertyHandlersFor(RegistrationForm2.USERPROPERTIES_FORM_IDENTIFIER, false);
-		finishVC.contextPut("userPropertyHandlers", userPropertyHandlers);
+		List<UserPropertyHandler> aggregatedUserPropertyHandlers = new ArrayList<>(userPropertyHandlers);
+		if(registrationAdditionalForm != null) {
+			List<UserPropertyHandler> addUserPropertyHandlers = userManager.getUserPropertyHandlersFor(RegistrationAdditionalForm.USERPROPERTIES_FORM_IDENTIFIER, false);
+			aggregatedUserPropertyHandlers.addAll(addUserPropertyHandlers);
+		}
+
+		VelocityContainer finishVC = createVelocityContainer("finish");
+		finishVC.contextPut("userPropertyHandlers", aggregatedUserPropertyHandlers);
 		finishVC.contextPut("user", persitedIdentity.getUser());
 		finishVC.contextPut("locale", getLocale());
 		finishVC.contextPut("username", registrationForm.getLogin());
@@ -491,7 +527,6 @@ public class RegistrationController extends BasicController implements Activatea
 			return null;
 		} else {
 			// update other user properties from form
-			List<UserPropertyHandler> userPropertyHandlers = userManager.getUserPropertyHandlersFor(RegistrationForm2.USERPROPERTIES_FORM_IDENTIFIER, false);
 			User persistedUser = persistedIdentity.getUser();
 			
 			//add eventually static value
@@ -510,10 +545,22 @@ public class RegistrationController extends BasicController implements Activatea
 				}
 			}
 
+			// add value of registration form
+			List<UserPropertyHandler> userPropertyHandlers = userManager.getUserPropertyHandlersFor(RegistrationForm2.USERPROPERTIES_FORM_IDENTIFIER, false);
 			for (UserPropertyHandler userPropertyHandler : userPropertyHandlers) {
 				FormItem fi = registrationForm.getPropFormItem(userPropertyHandler.getName());
 				userPropertyHandler.updateUserFromFormItem(persistedUser, fi);
 			}
+			
+			// add value of additional registration form
+			if(registrationAdditionalForm != null) {
+				List<UserPropertyHandler> addUserPropertyHandlers = userManager.getUserPropertyHandlersFor(RegistrationAdditionalForm.USERPROPERTIES_FORM_IDENTIFIER, false);
+				for (UserPropertyHandler userPropertyHandler : addUserPropertyHandlers) {
+					FormItem fi = registrationAdditionalForm.getPropFormItem(userPropertyHandler.getName());
+					userPropertyHandler.updateUserFromFormItem(persistedUser, fi);
+				}
+			}
+			
 			// persist changes in db
 			userManager.updateUserFromIdentity(persistedIdentity);
 			// send notification mail to sys admin
diff --git a/src/main/java/org/olat/registration/RegistrationForm2.java b/src/main/java/org/olat/registration/RegistrationForm2.java
index 8e665117855..70c8dbff7d8 100644
--- a/src/main/java/org/olat/registration/RegistrationForm2.java
+++ b/src/main/java/org/olat/registration/RegistrationForm2.java
@@ -58,10 +58,11 @@ import org.springframework.beans.factory.annotation.Autowired;
  * @author Sabina Jeger
  */
 public class RegistrationForm2 extends FormBasicController {
-	static final String USERPROPERTIES_FORM_IDENTIFIER = RegistrationForm2.class.getCanonicalName();
+	public static final String USERPROPERTIES_FORM_IDENTIFIER = RegistrationForm2.class.getCanonicalName();
+	
 	private String languageKey;
 	private List<UserPropertyHandler> userPropertyHandlers;
-	private Map <String,FormItem>propFormItems;
+	private final Map<String,FormItem> propFormItems = new HashMap<>();
 	
 	private SingleSelection lang;
 	private TextElement username;
@@ -72,14 +73,14 @@ public class RegistrationForm2 extends FormBasicController {
 	private final String proposedUsername;
 	private final boolean userInUse;
 	private final boolean usernameReadonly;
-	
-	private FormLayoutContainer buttonLayout;
 
 	@Autowired
 	private UserModule userModule;
 	@Autowired
 	private I18nManager i18nManager;
 	@Autowired
+	private UserManager userManager;
+	@Autowired
 	private BaseSecurity securityManager;
 	
 	/**
@@ -95,7 +96,6 @@ public class RegistrationForm2 extends FormBasicController {
 		this.userInUse = userInUse;
 		this.usernameReadonly = usernameReadonly;
 
-		propFormItems = new HashMap<>();
 		initForm(ureq);
 	}
 	
@@ -157,21 +157,16 @@ public class RegistrationForm2 extends FormBasicController {
 	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
 		setFormTitle("title.register");
 		// first the configured user properties
-		UserManager um = UserManager.getInstance();
-		userPropertyHandlers = um.getUserPropertyHandlersFor(USERPROPERTIES_FORM_IDENTIFIER, false);
+		userPropertyHandlers = userManager.getUserPropertyHandlersFor(USERPROPERTIES_FORM_IDENTIFIER, false);
 		
-		Translator tr = Util.createPackageTranslator(
-				UserPropertyHandler.class,
-				getLocale(), getTranslator()
-		);
+		Translator tr = Util.createPackageTranslator(UserPropertyHandler.class, getLocale(), getTranslator());
 		
 		// Add all available user fields to this form
 		for (UserPropertyHandler userPropertyHandler : userPropertyHandlers) {
 			if (userPropertyHandler == null) continue;
 			
-			FormItem fi = userPropertyHandler.addFormItem(
-					getLocale(), null, USERPROPERTIES_FORM_IDENTIFIER, false, formLayout
-			);
+			FormItem fi = userPropertyHandler
+					.addFormItem(getLocale(), null, USERPROPERTIES_FORM_IDENTIFIER, false, formLayout);
 			fi.setTranslator(tr);
 			propFormItems.put(userPropertyHandler.getName(), fi);
 		}
@@ -182,8 +177,7 @@ public class RegistrationForm2 extends FormBasicController {
 		lang = uifactory.addDropdownSingleselect("user.language", formLayout,
 				StringHelper.getMapKeysAsStringArray(languages),
 				StringHelper.getMapValuesAsStringArray(languages),
-				null
-		); 
+				null); 
 		lang.select(languageKey, true);
 		
 		uifactory.addSpacerElement("loginstuff", formLayout, true);
@@ -209,8 +203,9 @@ public class RegistrationForm2 extends FormBasicController {
 		newpass2.setAutocomplete("new-password");
 	
 		// Button layout
-		buttonLayout = FormLayoutContainer.createButtonLayout("button_layout", getTranslator());
+		FormLayoutContainer buttonLayout = FormLayoutContainer.createButtonLayout("button_layout", getTranslator());
 		formLayout.add(buttonLayout);
+		uifactory.addFormCancelButton("cancel", buttonLayout, ureq, getWindowControl());
 		uifactory.addFormSubmitButton("submit.speichernUndweiter", buttonLayout);
 			
 	}
@@ -257,13 +252,17 @@ public class RegistrationForm2 extends FormBasicController {
 		}
 		return true;
 	}
-	
-	
+
 	@Override
 	protected void formOK(UserRequest ureq) {
 		fireEvent (ureq, Event.DONE_EVENT);
 	}
 
+	@Override
+	protected void formCancelled(UserRequest ureq) {
+		fireEvent(ureq, Event.CANCELLED_EVENT);
+	}
+
 	@Override
 	protected void doDispose() {
 		//
diff --git a/src/main/java/org/olat/registration/_content/finish.html b/src/main/java/org/olat/registration/_content/finish.html
index 26d12eecdb1..0bb38ed6a0b 100644
--- a/src/main/java/org/olat/registration/_content/finish.html
+++ b/src/main/java/org/olat/registration/_content/finish.html
@@ -25,6 +25,6 @@
 		</table>
 	</div>
 </div>
-<div class="o_button_group o_button_group_left">
+<div class="o_button_group">
 	$r.render("loginhref")
 </div>
diff --git a/src/main/java/org/olat/registration/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/registration/_i18n/LocalStrings_de.properties
index 9e9e76a7447..ec9f1064d28 100644
--- a/src/main/java/org/olat/registration/_i18n/LocalStrings_de.properties
+++ b/src/main/java/org/olat/registration/_i18n/LocalStrings_de.properties
@@ -111,6 +111,8 @@ step4.pw.text=Sie haben Ihr OpenOLAT-Passwort neu gesetzt.
 step4.reg.text=<b>Bitte akzeptieren Sie die Nutzungsbedingungen, bevor Sie fortfahren.</b>
 step5.reg.text=Sie k\u00F6nnen sich nun mit Ihrem Benutzernamen <b>{0}</b> und Passwort anmelden\:
 step5.reg.yourdata=Zusammenfassung Ihrer Angaben\:
+step.add.reg.text=In Sprachanpassungswerkzeug <strong>org.olat.registration</strong> <strong>step.add.reg.text</strong>
+step.add.reg.title=In Sprachanpassungswerkzeug <strong>org.olat.registration</strong> <strong>step.add.reg.title</strong>
 submit.accept=Akzeptieren
 submit.cancel=Abbrechen
 submit.speichernUndpwchange=OpenOLAT-Passwort \u00E4ndern
diff --git a/src/main/java/org/olat/registration/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/registration/_i18n/LocalStrings_en.properties
index a51dbd82fce..f03b08322c9 100644
--- a/src/main/java/org/olat/registration/_i18n/LocalStrings_en.properties
+++ b/src/main/java/org/olat/registration/_i18n/LocalStrings_en.properties
@@ -111,6 +111,8 @@ step4.pw.text=You have changed your OpenOLAT password successfully.
 step4.reg.text=<b>Please read the terms of use before proceeding.</b>
 step5.reg.text=You can now log in with your OpenOLAT user name <b>{0}</b> and password\:
 step5.reg.yourdata=Summary of your data\:
+step.add.reg.text=In translation tool <strong>org.olat.registration</strong> <strong>step.add.reg.text</strong>
+step.add.reg.title=In translation tool <strong>org.olat.registration</strong> <strong>step.add.reg.title</strong>
 submit.accept=Accept
 submit.cancel=Cancel
 submit.speichernUndpwchange=Change OpenOLAT password
diff --git a/src/main/java/org/olat/user/propertyhandlers/_spring/userPropertiesContext.xml b/src/main/java/org/olat/user/propertyhandlers/_spring/userPropertiesContext.xml
index 4099b92686e..39b98190666 100644
--- a/src/main/java/org/olat/user/propertyhandlers/_spring/userPropertiesContext.xml
+++ b/src/main/java/org/olat/user/propertyhandlers/_spring/userPropertiesContext.xml
@@ -692,6 +692,7 @@
 				<!--  RegistrationForm2 is used in the self registration process -->
 				<entry key="org.olat.registration.RegistrationForm2">
 					<bean class="org.olat.user.propertyhandlers.UserPropertyUsageContext">
+						<property name="description" value="Registration form for self-registrated users" />
 						<property name="propertyHandlers">
 							<list>
 								<!--
@@ -710,6 +711,19 @@
 						</property>
 					</bean>
 				</entry>
+				
+				<!--  RegistrationForm2 is used in the self registration process -->
+				<entry key="org.olat.registration.RegistrationAdditionalForm">
+					<bean class="org.olat.user.propertyhandlers.UserPropertyUsageContext">
+						<property name="description" value="Additional registration form for self-registrated users (if empty, the step doesn't appear)" />
+						<property name="propertyHandlers">
+							<list />
+						</property>
+						<property name="mandatoryProperties">
+							<set />
+						</property>
+					</bean>
+				</entry>
 
 				<!--  OAuthRegistrationController is used in the OAuth registration process -->
 				<entry key="org.olat.login.oauth.ui.OAuthRegistrationController">
-- 
GitLab