diff --git a/src/main/java/org/olat/core/id/Identity.java b/src/main/java/org/olat/core/id/Identity.java index 3fa1da336ed8c2d9af9bc72cf8e8fc2631be77c3..e4b269251dfab6fde6e2da00814554ad76359cb1 100644 --- a/src/main/java/org/olat/core/id/Identity.java +++ b/src/main/java/org/olat/core/id/Identity.java @@ -38,18 +38,20 @@ import org.olat.basesecurity.IdentityRef; */ public interface Identity extends CreateInfo, IdentityRef, Persistable { - // status = 1..99 User with this status are visibale (e.g. user search) - // 100..199 User with this status are invisibale (e.g. user search) + // status = 1..99 User with this status are visible (e.g. user search) + // 100..199 User with this status are invisible (e.g. user search) /** Identity has a permanent olat user account and will be never listen in user-deletion process. */ - public static Integer STATUS_PERMANENT = 1; + public static final Integer STATUS_PERMANENT = 1; /** Identity has access to olat-system. */ - public static Integer STATUS_ACTIV = 2; + public static final Integer STATUS_ACTIV = 2; /** Limit for visible identities, all identities with status < LIMIT will be listed in search etc. */ - public static Integer STATUS_VISIBLE_LIMIT = 100; + public static final Integer STATUS_VISIBLE_LIMIT = 100; /** Identity can not login and will not be listed (only on login-denied list). */ - public static Integer STATUS_LOGIN_DENIED = 101; + public static final Integer STATUS_LOGIN_DENIED = 101; + /** Identity can not login and will not be listed (only on pending list). */ + public static final Integer STATUS_PENDING = 102; /** Identity is deleted and has no access to olat-system and is not visible (except administrators). */ - public static Integer STATUS_DELETED = 199; + public static final Integer STATUS_DELETED = 199; /** * @return The username, (login name, nickname..) diff --git a/src/main/java/org/olat/registration/RegistrationAdminController.java b/src/main/java/org/olat/registration/RegistrationAdminController.java index 54fabbedc6640836a2bd0c2b29dd076144be2d4c..5a44d3d5aaaa633df23845bf5fa1da12cf8daa22 100644 --- a/src/main/java/org/olat/registration/RegistrationAdminController.java +++ b/src/main/java/org/olat/registration/RegistrationAdminController.java @@ -41,6 +41,7 @@ import org.olat.core.gui.translator.Translator; import org.olat.core.helpers.Settings; import org.olat.core.id.Organisation; import org.olat.core.util.StringHelper; +import org.olat.core.util.mail.MailHelper; import org.olat.user.UserPropertiesConfig; import org.olat.user.propertyhandlers.Generic127CharTextPropertyHandler; import org.olat.user.propertyhandlers.UserPropertyHandler; @@ -59,17 +60,34 @@ public class RegistrationAdminController extends FormBasicController { private MultipleSelectionElement registrationLoginElement; private MultipleSelectionElement staticPropElement; private SingleSelection propertyElement; + private SingleSelection pendingRegistrationStatusEl; + private TextElement pendingRegistrationNotificationEl; + private PropertyNameValueElements pendingProperty1Els; + private PropertyNameValueElements pendingProperty2Els; + private PropertyNameValueElements pendingProperty3Els; + private PropertyNameValueElements pendingProperty4Els; + private PropertyNameValueElements pendingProperty5Els; private TextElement propertyValueElement; private TextElement exampleElement; private TextElement domainListElement; private TextElement validUntilGuiEl; private TextElement validUntilRestEl; private FormLayoutContainer domainsContainer; + private FormLayoutContainer pendingPropContainer; private FormLayoutContainer staticPropContainer; + + private static final String[] pendingRegistrationKeys = new String[] { + RegistrationPendingStatus.active.name(), + RegistrationPendingStatus.pending.name(), + RegistrationPendingStatus.pendingMatchingProperties.name() + }; + private static final String[] enableRegistrationKeys = new String[]{ "on" }; - private String[] propertyKeys; - private String[] propertyValues; + private final String[] propertyKeys; + private final String[] propertyValues; + private final String[] pendingPropertyKeys; + private final String[] pendingPropertyValues; @Autowired private RegistrationModule registrationModule; @@ -87,7 +105,6 @@ public class RegistrationAdminController extends FormBasicController { //decorate the translator userPropTranslator = userPropertiesConfig.getTranslator(getTranslator()); - List<UserPropertyHandler> allPropertyHandlers = userPropertiesConfig.getAllUserPropertyHandlers(); List<UserPropertyHandler> propertyHandlers = new ArrayList<>(allPropertyHandlers.size()); for(UserPropertyHandler handler:allPropertyHandlers) { @@ -106,6 +123,16 @@ public class RegistrationAdminController extends FormBasicController { propertyValues[1 + count++] = userPropTranslator.translate(propertyHandler.i18nFormElementLabelKey()); } + pendingPropertyKeys = new String[allPropertyHandlers.size() + 1]; + pendingPropertyValues = new String[allPropertyHandlers.size() + 1]; + count = 0; + pendingPropertyKeys[0] = "-"; + pendingPropertyValues[0] = ""; + for(UserPropertyHandler propertyHandler:allPropertyHandlers) { + pendingPropertyKeys[1 + count] = propertyHandler.getName(); + pendingPropertyValues[1 + count++] = userPropTranslator.translate(propertyHandler.i18nFormElementLabelKey()); + } + initForm(ureq); } @@ -141,7 +168,24 @@ public class RegistrationAdminController extends FormBasicController { String example = generateExampleCode(); exampleElement = uifactory.addTextAreaElement("registration.link.example", "admin.registrationLinkExample", 64000, 4, 65, true, false, example, settingsContainer); + // pedning status + initPendingPropForm(formLayout); //domain configuration + initDomainForm(formLayout); + //static property + initStaticPropForm(formLayout, enableRegistrationValues); + //static property + initRemoteLogin(formLayout); + + FormLayoutContainer buttonGroupLayout = FormLayoutContainer.createButtonLayout("buttons", getTranslator()); + buttonGroupLayout.setRootForm(mainForm); + uifactory.addFormSubmitButton("save", buttonGroupLayout); + formLayout.add(buttonGroupLayout); + + updateUI(); + } + + private void initDomainForm(FormItemContainer formLayout) { domainsContainer = FormLayoutContainer.createDefaultFormLayout("domains", getTranslator()); domainsContainer.setRootForm(mainForm); domainsContainer.setFormTitle(translate("admin.registration.domains.title")); @@ -150,8 +194,55 @@ public class RegistrationAdminController extends FormBasicController { uifactory.addStaticTextElement("admin.registration.domains.error", null, translate("admin.registration.domains.desc"), domainsContainer); String domainsList = registrationModule.getDomainListRaw(); domainListElement = uifactory.addTextAreaElement("registration.domain.list", "admin.registration.domains", 64000, 10, 65, true, false, domainsList, domainsContainer); + } + + private void initPendingPropForm(FormItemContainer formLayout) { + pendingPropContainer = FormLayoutContainer.createDefaultFormLayout("propertiespending", getTranslator()); + pendingPropContainer.setRootForm(mainForm); + pendingPropContainer.setFormTitle(translate("admin.registration.pending.status")); + formLayout.add(pendingPropContainer); + + String[] pendingRegistrationValues = new String[] { + translate("registration.pending.status.active"), + translate("registration.pending.status.pending"), + translate("registration.pending.status.pending.props") + }; + pendingRegistrationStatusEl = uifactory.addDropdownSingleselect("registration.pending.status", pendingPropContainer, pendingRegistrationKeys, pendingRegistrationValues); + pendingRegistrationStatusEl.select(registrationModule.getRegistrationPendingStatus().name(), true); + pendingRegistrationStatusEl.addActionListener(FormEvent.ONCHANGE); + + pendingProperty1Els = initPendingProperty(1, registrationModule.getRegistrationPendingPropertyName1(), registrationModule.getRegistrationPendingPropertyValue1(), pendingPropContainer); + pendingProperty2Els = initPendingProperty(2, registrationModule.getRegistrationPendingPropertyName2(), registrationModule.getRegistrationPendingPropertyValue2(), pendingPropContainer); + pendingProperty3Els = initPendingProperty(3, registrationModule.getRegistrationPendingPropertyName3(), registrationModule.getRegistrationPendingPropertyValue3(), pendingPropContainer); + pendingProperty4Els = initPendingProperty(4, registrationModule.getRegistrationPendingPropertyName4(), registrationModule.getRegistrationPendingPropertyValue4(), pendingPropContainer); + pendingProperty5Els = initPendingProperty(5, registrationModule.getRegistrationPendingPropertyName5(), registrationModule.getRegistrationPendingPropertyValue5(), pendingPropContainer); - //static property + String email = ""; + if(registrationModule.isRegistrationNotificationEmailEnabled()) { + email = registrationModule.getRegistrationNotificationEmail(); + } + pendingRegistrationNotificationEl = uifactory.addTextElement("registration.pending.notification.mail", 2048, email, pendingPropContainer); + } + + private PropertyNameValueElements initPendingProperty(int pos, String propName, String propValue, FormLayoutContainer formLayout) { + SingleSelection pendingPropertyNameEl = uifactory.addDropdownSingleselect("registration.pending.prop.name" + pos, formLayout, pendingPropertyKeys, pendingPropertyValues); + boolean found = false; + for(int i=pendingPropertyKeys.length; i-->0; ) { + if(pendingPropertyKeys[i].equals(propName)) { + pendingPropertyNameEl.select(pendingPropertyKeys[i], true); + found = true; + break; + } + } + if(!found) { + pendingPropertyNameEl.select(pendingPropertyKeys[0], true); + } + + TextElement pendingPropertyValueEl = uifactory.addTextElement("registration.pending.prop.value" + pos, 2048, propValue, formLayout); + return new PropertyNameValueElements(pendingPropertyNameEl, pendingPropertyValueEl); + } + + private void initStaticPropForm(FormItemContainer formLayout, String[] enableRegistrationValues) { staticPropContainer = FormLayoutContainer.createDefaultFormLayout("propertiesmapping", getTranslator()); staticPropContainer.setRootForm(mainForm); staticPropContainer.setFormTitle(translate("admin.registration.staticprop.title")); @@ -173,8 +264,9 @@ public class RegistrationAdminController extends FormBasicController { String propertyValue = registrationModule.getStaticPropertyMappingValue(); propertyValueElement = uifactory.addTextElement("admin.registration.prop.value", "admin.registration.propertyValue", 255, propertyValue, staticPropContainer); - - //static property + } + + private void initRemoteLogin(FormItemContainer formLayout) { FormLayoutContainer remoteLoginContainerContainer = FormLayoutContainer.createDefaultFormLayout("remotelogin", getTranslator()); remoteLoginContainerContainer.setRootForm(mainForm); remoteLoginContainerContainer.setFormTitle(translate("remote.login.title")); @@ -182,13 +274,6 @@ public class RegistrationAdminController extends FormBasicController { String remoteExample = generateRemoteLoginExampleCode(); uifactory.addTextAreaElement("remotelogin.example", "admin.registrationLinkExample", 64000, 4, 65, true, false, remoteExample, remoteLoginContainerContainer); - - FormLayoutContainer buttonGroupLayout = FormLayoutContainer.createButtonLayout("buttons", getTranslator()); - buttonGroupLayout.setRootForm(mainForm); - uifactory.addFormSubmitButton("save", buttonGroupLayout); - formLayout.add(buttonGroupLayout); - - updateUI(); } private void initOrganisationsEl(FormLayoutContainer formLayout) { @@ -232,6 +317,8 @@ public class RegistrationAdminController extends FormBasicController { } else if (source == staticPropElement) { registrationModule.setStaticPropertyMappingEnabled(staticPropElement.isSelected(0)); updateUI(); + } else if(source == pendingRegistrationStatusEl) { + updateUI(); } super.formInnerEvent(ureq, source, event); @@ -249,6 +336,17 @@ public class RegistrationAdminController extends FormBasicController { boolean enableDomains = enableMain && (registrationLinkElement.isSelected(0) || registrationLoginElement.isSelected(0)); domainsContainer.setVisible(enableDomains); + pendingPropContainer.setVisible(enableMain); + if(enableMain) { + boolean useProps = RegistrationPendingStatus.pendingMatchingProperties.name() + .equals(pendingRegistrationStatusEl.getSelectedKey()); + pendingProperty1Els.setVisible(useProps); + pendingProperty2Els.setVisible(useProps); + pendingProperty3Els.setVisible(useProps); + pendingProperty4Els.setVisible(useProps); + pendingProperty5Els.setVisible(useProps); + } + //static prop boolean enableProps = enableMain && (registrationLinkElement.isSelected(0) || registrationLoginElement.isSelected(0)); staticPropContainer.setVisible(enableProps); @@ -264,6 +362,14 @@ public class RegistrationAdminController extends FormBasicController { allOk &= validateInteger(validUntilGuiEl, 1); allOk &= validateInteger(validUntilRestEl, 1); + allOk &= validatePropertyNameValuePair(pendingProperty1Els); + allOk &= validatePropertyNameValuePair(pendingProperty2Els); + allOk &= validatePropertyNameValuePair(pendingProperty3Els); + allOk &= validatePropertyNameValuePair(pendingProperty4Els); + allOk &= validatePropertyNameValuePair(pendingProperty5Els); + + allOk &= validateEmail(pendingRegistrationNotificationEl); + String whiteList = domainListElement.getValue(); domainListElement.clearError(); if(StringHelper.containsNonWhitespace(whiteList)) { @@ -305,6 +411,44 @@ public class RegistrationAdminController extends FormBasicController { return allOk; } + private boolean validateEmail(TextElement el) { + boolean allOk = true; + + el.clearError(); + if(StringHelper.containsNonWhitespace(el.getValue())) { + String[] emails = el.getValue().split("[,]"); + for(String email:emails) { + if(!MailHelper.isValidEmailAddress(email)) { + el.setErrorKey("email.address.notregular", null); + allOk &= false; + break; + } + } + } + + return allOk; + } + + private boolean validatePropertyNameValuePair(PropertyNameValueElements nameValueEls) { + boolean allOk = true; + + SingleSelection nameEl = nameValueEls.getPropertyNameEl(); + TextElement valueEl = nameValueEls.getPropertyValueEl(); + + nameEl.clearError(); + valueEl.clearError(); + if(!nameEl.isOneSelected()) { + nameEl.setErrorKey("form.legende.mandatory", null); + allOk &= false; + } else if(!nameEl.getSelectedKey().equals(propertyKeys[0]) + && !StringHelper.containsNonWhitespace(valueEl.getValue())) { + valueEl.setErrorKey("form.legende.mandatory", null); + allOk &= false; + } + + return allOk; + } + private boolean validateInteger(TextElement el, int min) { boolean allOk = true; el.clearError(); @@ -336,6 +480,23 @@ public class RegistrationAdminController extends FormBasicController { if(organisationsEl.isOneSelected()) { registrationModule.setselfRegistrationOrganisationKey(organisationsEl.getSelectedKey()); } + if(pendingRegistrationStatusEl.isOneSelected()) { + registrationModule.setRegistrationPendingStatus(RegistrationPendingStatus.valueOf(pendingRegistrationStatusEl.getSelectedKey())); + } + + registrationModule.setRegistrationPendingProperty1(pendingProperty1Els.getName(), pendingProperty1Els.getValue()); + registrationModule.setRegistrationPendingProperty2(pendingProperty2Els.getName(), pendingProperty2Els.getValue()); + registrationModule.setRegistrationPendingProperty3(pendingProperty3Els.getName(), pendingProperty3Els.getValue()); + registrationModule.setRegistrationPendingProperty4(pendingProperty4Els.getName(), pendingProperty4Els.getValue()); + registrationModule.setRegistrationPendingProperty5(pendingProperty5Els.getName(), pendingProperty5Els.getValue()); + + String notificationEmail = pendingRegistrationNotificationEl.getValue(); + if(StringHelper.containsNonWhitespace(notificationEmail)) { + registrationModule.setRegistrationNotificationEmailEnabled(true); + registrationModule.setRegistrationNotificationEmail(notificationEmail); + } else { + registrationModule.setRegistrationNotificationEmailEnabled(false); + } Integer validUntilHoursGui = Integer.parseInt(validUntilGuiEl.getValue()); registrationModule.setValidUntilHoursGui(validUntilHoursGui); @@ -375,4 +536,40 @@ public class RegistrationAdminController extends FormBasicController { .append("</form>"); return code.toString(); } + + public class PropertyNameValueElements { + + private final SingleSelection propertyNameEl; + private final TextElement propertyValueEl; + + public PropertyNameValueElements(SingleSelection propertyNameEl, TextElement propertyValueEl) { + this.propertyNameEl = propertyNameEl; + this.propertyValueEl = propertyValueEl; + } + + public SingleSelection getPropertyNameEl() { + return propertyNameEl; + } + + public TextElement getPropertyValueEl() { + return propertyValueEl; + } + + public void setVisible(boolean visible) { + propertyNameEl.setVisible(visible); + propertyValueEl.setVisible(visible); + } + + public String getName() { + String key = propertyNameEl.getSelectedKey(); + if(propertyKeys[0].equals(key)) { + key = ""; + } + return key; + } + + public String getValue() { + return propertyValueEl.getValue(); + } + } } diff --git a/src/main/java/org/olat/registration/RegistrationController.java b/src/main/java/org/olat/registration/RegistrationController.java index 15ea45a05ced4714aba7fedec4fc689409e1a5d7..b309c8515e157c721fc0db52406db0cf91be61a0 100644 --- a/src/main/java/org/olat/registration/RegistrationController.java +++ b/src/main/java/org/olat/registration/RegistrationController.java @@ -37,7 +37,6 @@ import java.util.Map; import org.olat.basesecurity.AuthHelper; import org.olat.basesecurity.BaseSecurity; 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; @@ -122,6 +121,8 @@ public class RegistrationController extends BasicController implements Activatea private RegistrationModule registrationModule; @Autowired private RegistrationManager registrationManager; + @Autowired + private UserPropertiesConfig userPropertiesConfig; /** * Controller implementing registration workflow. @@ -495,7 +496,14 @@ public class RegistrationController extends BasicController implements Activatea 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() })); + + boolean pending = persitedIdentity.getStatus().equals(Identity.STATUS_PENDING); + if(pending) { + finishVC.contextPut("text", translate("step5.reg.pending", new String[]{ registrationForm.getLogin() })); + } else { + finishVC.contextPut("text", translate("step5.reg.text", new String[]{ registrationForm.getLogin() })); + } + finishVC.contextPut("pending", Boolean.valueOf(pending)); loginButton = LinkFactory.createButton("form.login", finishVC, this); loginButton.setCustomEnabledLinkCSS("btn btn-primary"); loginButton.setUserObject(persitedIdentity); @@ -530,7 +538,6 @@ public class RegistrationController extends BasicController implements Activatea 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(); @@ -564,7 +571,7 @@ public class RegistrationController extends BasicController implements Activatea // persist changes in db userManager.updateUserFromIdentity(persistedIdentity); // send notification mail to sys admin - String notiEmail = CoreSpringFactory.getImpl(RegistrationModule.class).getRegistrationNotificationEmail(); + String notiEmail = registrationModule.getRegistrationNotificationEmail(); if (notiEmail != null) { registrationManager.sendNewUserNotificationMessage(notiEmail, persistedIdentity); } diff --git a/src/main/java/org/olat/registration/RegistrationManager.java b/src/main/java/org/olat/registration/RegistrationManager.java index 25c29416c1e50a48b35e2c389245f1cf912de4ec..9b482c098342fe0d940878a7010a7becb8896bcf 100644 --- a/src/main/java/org/olat/registration/RegistrationManager.java +++ b/src/main/java/org/olat/registration/RegistrationManager.java @@ -47,7 +47,6 @@ import org.olat.basesecurity.BaseSecurity; import org.olat.basesecurity.OrganisationRoles; import org.olat.basesecurity.OrganisationService; import org.olat.basesecurity.model.OrganisationRefImpl; -import org.olat.core.CoreSpringFactory; import org.olat.core.commons.persistence.DB; import org.olat.core.gui.translator.Translator; import org.olat.core.helpers.Settings; @@ -88,6 +87,11 @@ import com.thoughtworks.xstream.XStream; public class RegistrationManager implements UserDataDeletable, UserDataExportable { private static final OLog log = Tracing.createLoggerFor(RegistrationManager.class); + + private static final XStream xmlXStream = XStreamHelper.createXStreamInstance(); + static { + XStream.setupDefaultSecurity(xmlXStream); + } private static final int VALID_UNTIL_30_DAYS = 30*24; @@ -98,6 +102,8 @@ public class RegistrationManager implements UserDataDeletable, UserDataExportabl @Autowired private DB dbInstance; @Autowired + private I18nModule i18nModule; + @Autowired private MailManager mailManager; @Autowired private BaseSecurity securityManager; @@ -204,14 +210,53 @@ public class RegistrationManager implements UserDataDeletable, UserDataExportabl } if (identity == null) { return null; + } else if(pending(identity)) { + identity = securityManager.saveIdentityStatus(identity, Identity.STATUS_PENDING, identity); } deleteTemporaryKey(tk); return identity; } + + private boolean pending(Identity identity) { + boolean pending = false; + RegistrationPendingStatus status = registrationModule.getRegistrationPendingStatus(); + if(status == RegistrationPendingStatus.pending) { + pending = true; + } else if(status == RegistrationPendingStatus.pendingMatchingProperties) { + User user = identity.getUser(); + @SuppressWarnings("static-access") + Locale locale = i18nModule.getDefaultLocale(); + pending |= matchProperty(user, registrationModule.getRegistrationPendingPropertyName1(), registrationModule.getRegistrationPendingPropertyValue1(), locale); + pending |= matchProperty(user, registrationModule.getRegistrationPendingPropertyName2(), registrationModule.getRegistrationPendingPropertyValue2(), locale); + pending |= matchProperty(user, registrationModule.getRegistrationPendingPropertyName3(), registrationModule.getRegistrationPendingPropertyValue3(), locale); + pending |= matchProperty(user, registrationModule.getRegistrationPendingPropertyName4(), registrationModule.getRegistrationPendingPropertyValue4(), locale); + pending |= matchProperty(user, registrationModule.getRegistrationPendingPropertyName5(), registrationModule.getRegistrationPendingPropertyValue5(), locale); + } + return pending; + } + + private boolean matchProperty(User user, String propName, String propValue, Locale locale) { + boolean match = false; + + if(StringHelper.containsNonWhitespace(propName) && StringHelper.containsNonWhitespace(propValue)) { + String val = user.getProperty(propName, locale); + + if(propValue.equalsIgnoreCase(val)) { + match = true; + } else if(UserConstants.EMAIL.equals(propName) || UserConstants.INSTITUTIONALEMAIL.equals(propName)) { + String valLow = val.toLowerCase(); + String propValueLow = propValue.toLowerCase(); + match = valLow.contains(propValueLow); + } + } + + return match; + } /** - * Send a notification messaged to the given notification email address about the registratoin of + * Send a notification messaged to the given notification email address about the registration of * the given new identity. + * * @param notificationMailAddress Email address who should be notified. MUST NOT BE NULL * @param newIdentity The newly registered Identity */ @@ -219,9 +264,15 @@ public class RegistrationManager implements UserDataDeletable, UserDataExportabl Address from; Address[] to; try { - // fxdiff: change from/replyto, see FXOLAT-74 from = new InternetAddress(WebappHelper.getMailConfig("mailReplyTo")); - to = new Address[] { new InternetAddress(notificationMailAddress)}; + String[] notificationMailAddressArr = notificationMailAddress.split("[,]"); + List<Address> toList = new ArrayList<>(); + for(int i=notificationMailAddressArr.length; i-->0; ) { + if(StringHelper.containsNonWhitespace(notificationMailAddressArr[i])) { + toList.add(new InternetAddress(notificationMailAddressArr[i])); + } + } + to = toList.toArray(new Address[toList.size()]); } catch (AddressException e) { log.error("Could not send registration notification message, bad mail address", e); return; @@ -427,12 +478,9 @@ public class RegistrationManager implements UserDataDeletable, UserDataExportabl public boolean isEmailReserved(String emailAddress) { if (!StringHelper.containsNonWhitespace(emailAddress)) return false; - RegistrationManager rm = CoreSpringFactory.getImpl(RegistrationManager.class); - List<TemporaryKey> tk = rm.loadTemporaryKeyByAction(RegistrationManager.EMAIL_CHANGE); + List<TemporaryKey> tk = loadTemporaryKeyByAction(RegistrationManager.EMAIL_CHANGE); for (TemporaryKey temporaryKey : tk) { - XStream xml = XStreamHelper.createXStreamInstance(); - @SuppressWarnings("unchecked") - Map<String, String> mails = (Map<String, String>) xml.fromXML(temporaryKey.getEmailAddress()); + Map<String, String> mails = readTemporaryValue(temporaryKey.getEmailAddress()); if (emailAddress.equalsIgnoreCase(mails.get("changedEMail"))) { return true; } @@ -498,6 +546,11 @@ public class RegistrationManager implements UserDataDeletable, UserDataExportabl public void revokeConfirmedDisclaimer(Identity identity) { propertyManager.deleteProperties(identity, null, null, "user", "dislaimer_accepted"); } + + @SuppressWarnings("unchecked") + public Map<String, String> readTemporaryValue(String value) { + return (Map<String, String>)xmlXStream.fromXML(value); + } private String createRegistrationKey(String email, String ip) { String random = UUID.randomUUID().toString(); diff --git a/src/main/java/org/olat/registration/RegistrationModule.java b/src/main/java/org/olat/registration/RegistrationModule.java index 1d4300a9b5d5a3bf667c3123a6e9b5edc82aedab..81f09125146753adb20fcc1b31c02399735ff78b 100644 --- a/src/main/java/org/olat/registration/RegistrationModule.java +++ b/src/main/java/org/olat/registration/RegistrationModule.java @@ -74,6 +74,28 @@ public class RegistrationModule extends AbstractSpringModule { private boolean registrationNotificationEmailEnabled; @Value("${registration.notificationEmail}") private String registrationNotificationEmail; + @Value("${registration.pending.status:active}") + private String registrationPendingStatus; + @Value("${registration.pending.property.name1:}") + private String registrationPendingPropertyName1; + @Value("${registration.pending.property.value1:}") + private String registrationPendingPropertyValue1; + @Value("${registration.pending.property.name2:}") + private String registrationPendingPropertyName2; + @Value("${registration.pending.property.value2:}") + private String registrationPendingPropertyValue2; + @Value("${registration.pending.property.name3:}") + private String registrationPendingPropertyName3; + @Value("${registration.pending.property.value3:}") + private String registrationPendingPropertyValue3; + @Value("${registration.pending.property.name4:}") + private String registrationPendingPropertyName4; + @Value("${registration.pending.property.value4:}") + private String registrationPendingPropertyValue4; + @Value("${registration.pending.property.name5:}") + private String registrationPendingPropertyName5; + @Value("${registration.pending.property.value5:}") + private String registrationPendingPropertyValue5; @Value("${registration.staticPropertyMapping:false}") private boolean staticPropertyMappingEnabled; @@ -213,6 +235,30 @@ public class RegistrationModule extends AbstractSpringModule { public String getRegistrationNotificationEmail() { return registrationNotificationEmail; } + + public void setRegistrationNotificationEmail(String email) { + registrationNotificationEmail = email; + setStringProperty("registration.notificationEmail", email, true); + } + + public boolean isRegistrationNotificationEmailEnabled() { + return registrationNotificationEmailEnabled; + } + + public void setRegistrationNotificationEmailEnabled(boolean enabled) { + String enabledStr = enabled ? "true" : "false"; + registrationNotificationEmailEnabled = enabled; + setStringProperty("registration.enableNotificationEmail", enabledStr, true); + } + + public RegistrationPendingStatus getRegistrationPendingStatus() { + return RegistrationPendingStatus.valueOf(registrationPendingStatus); + } + + public void setRegistrationPendingStatus(RegistrationPendingStatus status) { + this.registrationPendingStatus = status.name(); + setStringProperty("registration.pending.status", status.name(), true); + } /** * @return true to force acceptance of disclaimer on first login; true to skip disclaimer @@ -251,6 +297,81 @@ public class RegistrationModule extends AbstractSpringModule { setStringProperty("registration.organisation.key", key, true); } + public String getRegistrationPendingPropertyName1() { + return registrationPendingPropertyName1; + } + + public void setRegistrationPendingProperty1(String propertyName, String propertyValue) { + this.registrationPendingPropertyName1 = propertyName; + this.registrationPendingPropertyValue1 = propertyValue; + setStringProperty("registration.pending.property.name1", propertyName, false); + setStringProperty("registration.pending.property.value1", propertyValue, true); + } + + public String getRegistrationPendingPropertyValue1() { + return registrationPendingPropertyValue1; + } + + public String getRegistrationPendingPropertyName2() { + return registrationPendingPropertyName2; + } + + public void setRegistrationPendingProperty2(String propertyName, String propertyValue) { + this.registrationPendingPropertyName2 = propertyName; + this.registrationPendingPropertyValue2 = propertyValue; + setStringProperty("registration.pending.property.name2", propertyName, false); + setStringProperty("registration.pending.property.value2", propertyValue, true); + } + + public String getRegistrationPendingPropertyValue2() { + return registrationPendingPropertyValue2; + } + + public String getRegistrationPendingPropertyName3() { + return registrationPendingPropertyName3; + } + + public void setRegistrationPendingProperty3(String propertyName, String propertyValue) { + this.registrationPendingPropertyName3 = propertyName; + this.registrationPendingPropertyValue3 = propertyValue; + setStringProperty("registration.pending.property.name3", propertyName, false); + setStringProperty("registration.pending.property.value3", propertyValue, true); + } + + public String getRegistrationPendingPropertyValue3() { + return registrationPendingPropertyValue3; + } + + public String getRegistrationPendingPropertyName4() { + return registrationPendingPropertyName4; + } + + public void setRegistrationPendingProperty4(String propertyName, String propertyValue) { + this.registrationPendingPropertyName4 = propertyName; + this.registrationPendingPropertyValue4 = propertyValue; + setStringProperty("registration.pending.property.name4", propertyName, false); + setStringProperty("registration.pending.property.value4", propertyValue, true); + } + + public String getRegistrationPendingPropertyValue4() { + return registrationPendingPropertyValue4; + } + + public String getRegistrationPendingPropertyName5() { + return registrationPendingPropertyName5; + } + + public void setRegistrationPendingProperty5(String propertyName, String propertyValue) { + this.registrationPendingPropertyName5 = propertyName; + this.registrationPendingPropertyValue5 = propertyValue; + setStringProperty("registration.pending.property.name5", propertyName, false); + setStringProperty("registration.pending.property.value5", propertyValue, true); + } + + public String getRegistrationPendingPropertyValue5() { + return registrationPendingPropertyValue5; + } + @Override public void init() { //registration enabled/disabled @@ -270,6 +391,56 @@ public class RegistrationModule extends AbstractSpringModule { if(StringHelper.containsNonWhitespace(loginEnabledObj)) { selfRegistrationLoginEnabled = "true".equals(loginEnabledObj); } + + String enableNotificationEmailObj = getStringPropertyValue("registration.enableNotificationEmail", true); + if(StringHelper.containsNonWhitespace(enableNotificationEmailObj)) { + registrationNotificationEmailEnabled = "true".equals(enableNotificationEmailObj); + } + + String notificationEmailObj = getStringPropertyValue("registration.notificationEmail", true); + if(StringHelper.containsNonWhitespace(notificationEmailObj)) { + registrationNotificationEmail = notificationEmailObj; + } + + String pendingPropName1Obj = getStringPropertyValue("registration.pending.property.name1", true); + String pendingPropValue1Obj = getStringPropertyValue("registration.pending.property.value1", true); + if(StringHelper.containsNonWhitespace(pendingPropName1Obj) && StringHelper.containsNonWhitespace(pendingPropValue1Obj)) { + registrationPendingPropertyName1 = pendingPropName1Obj; + registrationPendingPropertyValue1 = pendingPropValue1Obj; + } + + String pendingPropName2Obj = getStringPropertyValue("registration.pending.property.name2", true); + String pendingPropValue2Obj = getStringPropertyValue("registration.pending.property.value2", true); + if(StringHelper.containsNonWhitespace(pendingPropName2Obj) && StringHelper.containsNonWhitespace(pendingPropValue2Obj)) { + registrationPendingPropertyName2 = pendingPropName2Obj; + registrationPendingPropertyValue2 = pendingPropValue2Obj; + } + + String pendingPropName3Obj = getStringPropertyValue("registration.pending.property.name3", true); + String pendingPropValue3Obj = getStringPropertyValue("registration.pending.property.value3", true); + if(StringHelper.containsNonWhitespace(pendingPropName3Obj) && StringHelper.containsNonWhitespace(pendingPropValue3Obj)) { + registrationPendingPropertyName3 = pendingPropName3Obj; + registrationPendingPropertyValue3 = pendingPropValue3Obj; + } + + String pendingPropName4Obj = getStringPropertyValue("registration.pending.property.name4", true); + String pendingPropValue4Obj = getStringPropertyValue("registration.pending.property.value4", true); + if(StringHelper.containsNonWhitespace(pendingPropName4Obj) && StringHelper.containsNonWhitespace(pendingPropValue4Obj)) { + registrationPendingPropertyName4 = pendingPropName4Obj; + registrationPendingPropertyValue4 = pendingPropValue4Obj; + } + + String pendingPropName5Obj = getStringPropertyValue("registration.pending.property.name5", true); + String pendingPropValue5Obj = getStringPropertyValue("registration.pending.property.value5", true); + if(StringHelper.containsNonWhitespace(pendingPropName5Obj) && StringHelper.containsNonWhitespace(pendingPropValue5Obj)) { + registrationPendingPropertyName5 = pendingPropName5Obj; + registrationPendingPropertyValue5 = pendingPropValue5Obj; + } + + String pendingStatusObj = getStringPropertyValue("registration.pending.status", true); + if(StringHelper.containsNonWhitespace(pendingStatusObj)) { + registrationPendingStatus = pendingStatusObj; + } String organisationObj = getStringPropertyValue("registration.organisation.key", false); if(StringHelper.containsNonWhitespace(organisationObj)) { diff --git a/src/main/java/org/olat/registration/RegistrationPendingStatus.java b/src/main/java/org/olat/registration/RegistrationPendingStatus.java new file mode 100644 index 0000000000000000000000000000000000000000..f5c8387d678f6b259cc6f74a90ac32b754e6a2fb --- /dev/null +++ b/src/main/java/org/olat/registration/RegistrationPendingStatus.java @@ -0,0 +1,34 @@ +/** + * <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; + +/** + * + * Initial date: 14 déc. 2018<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public enum RegistrationPendingStatus { + + active, + pending, + pendingMatchingProperties + +} diff --git a/src/main/java/org/olat/registration/_content/admin.html b/src/main/java/org/olat/registration/_content/admin.html index b2506f1a1880075f4c586537ecc6a4f5c357975a..29fc2e080de71b7765b67f6babd7364e02dbe3c6 100644 --- a/src/main/java/org/olat/registration/_content/admin.html +++ b/src/main/java/org/olat/registration/_content/admin.html @@ -1,5 +1,6 @@ $r.render("settings") $r.render("domains") +$r.render("propertiespending") $r.render("propertiesmapping") $r.render("remotelogin") $r.render("buttons") \ No newline at end of file diff --git a/src/main/java/org/olat/registration/_content/finish.html b/src/main/java/org/olat/registration/_content/finish.html index 0bb38ed6a0b551818ad6754070d887fc77aab9dd..68a6160ed0e1366c8e01e587968d40d198c6d121 100644 --- a/src/main/java/org/olat/registration/_content/finish.html +++ b/src/main/java/org/olat/registration/_content/finish.html @@ -8,7 +8,7 @@ <div class="panel-heading"> <h4 class="panel-title">$r.translate("step5.reg.yourdata")</h4> </div> - <div class="panel-body"> + <div class="panel-body #if($r.isTrue($pending)) o_important #end"> <p>$text</p> </div> <table class="table table-bordered"> @@ -25,6 +25,8 @@ </table> </div> </div> +#if($r.isFalse($pending)) <div class="o_button_group"> $r.render("loginhref") </div> +#end 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 ec9f1064d28602df0644b3742b649b8a3c304c55..f9a4e7e8a4896745c46a9c1d415e4b1b6ba75324 100644 --- a/src/main/java/org/olat/registration/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/registration/_i18n/LocalStrings_de.properties @@ -10,6 +10,7 @@ admin.registration.domains=Dom\u00E4nenliste admin.registration.domains.desc=Die Selbtregistration kann optional auf eine oder mehrere Dom\u00E4nen eingeschr\u00E4nkt werden. Um diese Funktion zu aktivieren f\u00FCgen Sie eine Liste von Dom\u00E4nen an z.B\: openolat.com, *openolat.org, hotmail.com admin.registration.domains.error=Diese Dom\u00E4nen sind nicht g\u00FCltig\: {0} admin.registration.domains.title=Einschr\u00E4nkung auf Dom\u00E4ne +admin.registration.pending.status=Benutzerstatus admin.registration.property=Benutzerattribut admin.registration.propertyValue=Standardwert admin.registration.propertyValue.error=Ung\u00FCltiger Wert @@ -91,6 +92,21 @@ reg.notiEmail.subject=Neuer OpenOLAT-Benutzer\: {1} {2} ({0}) reg.subject=Registrierungsschl\u00FCssel f\u00FCr OpenOLAT reg.wherefrom=Diese Anfrage an den Server {0} wurde am {1} \nvon der IP-Adresse {2} abgeschickt. registration.form.cancelled=Sie haben die Registrierung abgebrochen. +registration.pending.notification.mail=Pending user creation notification email +registration.pending.prop.name1=Benutzer-Attributename 1 +registration.pending.prop.name2=Benutzer-Attributename 2 +registration.pending.prop.name3=Benutzer-Attributename 3 +registration.pending.prop.name4=Benutzer-Attributename 4 +registration.pending.prop.name5=Benutzer-Attributename 5 +registration.pending.prop.value1=Benutzer-Attributewert 1 +registration.pending.prop.value2=Benutzer-Attributewert 2 +registration.pending.prop.value3=Benutzer-Attributewert 3 +registration.pending.prop.value4=Benutzer-Attributewert 4 +registration.pending.prop.value5=Benutzer-Attributewert 5 +registration.pending.status=User state after self registration +registration.pending.status.active=Active +registration.pending.status.pending=H\u00E4ngig +registration.pending.status.pending.props=H\u00E4ngig wenn ein von den folgenden Benutzerproperties stimmt regkey.missing=Der Registrierungsschl\u00FCssel fehlt. Fordern Sie bitte einen neuen an. regkey.missingentry=Dieser Registrierungsschl\u00FCssel existiert nicht. Bitte fordern Sie einen neuen an. remote.login.title=Loginformular in externe Webseite/CMS einbinden @@ -109,6 +125,7 @@ step3.pw.text=Bitte beachten Sie bei der Eingabe des neuen OpenOLAT-Passwortes f step3.reg.text=Um die Registrierung abzuschliessen, f\u00FCllen Sie bitte das Formular mit Ihren Angaben aus. 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.pending=Anmeldung ist pending. 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> 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 f03b08322c9e10e2afe0c12ed131d4e2b73df90a..d845de3cc28914e64a3c501ec07a5f27bafa096b 100644 --- a/src/main/java/org/olat/registration/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/registration/_i18n/LocalStrings_en.properties @@ -10,6 +10,7 @@ admin.registration.domains=List of domains admin.registration.domains.desc=Optionally the self registration can be limited to one or multiple domains. To activate this feature add a list of domains into the form below, e.g. \: openolat.com, *openolat.org, hotmail.com admin.registration.domains.error=The following domains are not valid\: {0} admin.registration.domains.title=Domain limitation +admin.registration.pending.status=User status admin.registration.property=User property name admin.registration.propertyValue=User property value admin.registration.propertyValue.error=Invalid user property value @@ -91,6 +92,21 @@ reg.notiEmail.subject=New OpenOLAT user\: {1} {2} ({0}) reg.subject=Registration key for OpenOLAT reg.wherefrom=This registration request to the server {0} was made on {1} \nfrom the IP address {2}. registration.form.cancelled=You have cancelled the registration process. +registration.pending.notification.mail=Pending user creation notification email +registration.pending.prop.name1=User property name 1 +registration.pending.prop.name2=User property name 2 +registration.pending.prop.name3=User property name 3 +registration.pending.prop.name4=User property name 4 +registration.pending.prop.name5=User property name 5 +registration.pending.prop.value1=User property value 1 +registration.pending.prop.value2=User property value 2 +registration.pending.prop.value3=User property value 3 +registration.pending.prop.value4=User property value 4 +registration.pending.prop.value5=User property value 5 +registration.pending.status=User state after self registration +registration.pending.status.active=Active +registration.pending.status.pending=Pending +registration.pending.status.pending.props=Pending if one of the following user properties matches regkey.missing=Registration key missing. Please ask for a new one. regkey.missingentry=This registration key does not exist. Please ask for another one. remote.login.title=Embed login form into external website/CMS @@ -108,6 +124,7 @@ step2.reg.text=Thank you for your interest in OpenOLAT. You will receive an e-ma step3.pw.text=Please consider the following instructions for setting an OpenOLAT password\: step3.reg.text=In order to finish your registration, please fill in the form. step4.pw.text=You have changed your OpenOLAT password successfully. +step5.reg.pending=Registration is pending. 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\: