diff --git a/src/main/java/org/olat/core/commons/services/sms/MessagesSPI.java b/src/main/java/org/olat/core/commons/services/sms/MessagesSPI.java index eb01136e15c50eb2926b00352b414e7e6a2a5534..12d4f3da98dd03eea521dad838fd6944bafa8689 100644 --- a/src/main/java/org/olat/core/commons/services/sms/MessagesSPI.java +++ b/src/main/java/org/olat/core/commons/services/sms/MessagesSPI.java @@ -19,6 +19,11 @@ */ package org.olat.core.commons.services.sms; +import org.olat.core.commons.services.sms.ui.AbstractSMSConfigurationController; +import org.olat.core.gui.UserRequest; +import org.olat.core.gui.components.form.flexible.impl.Form; +import org.olat.core.gui.control.WindowControl; + /** * * Initial date: 3 févr. 2017<br> @@ -32,6 +37,8 @@ public interface MessagesSPI { public String getName(); public boolean isValid(); + + public AbstractSMSConfigurationController getConfigurationController(UserRequest ureq, WindowControl wControl, Form form); public boolean send(String messageId, String text, String recipient) throws SimpleMessageException; diff --git a/src/main/java/org/olat/core/commons/services/sms/SimpleMessageModule.java b/src/main/java/org/olat/core/commons/services/sms/SimpleMessageModule.java index f351063650fa14fe8cd41833aff034e9a0c8e728..19403fb277b6668390ddb86575447570c5825bac 100644 --- a/src/main/java/org/olat/core/commons/services/sms/SimpleMessageModule.java +++ b/src/main/java/org/olat/core/commons/services/sms/SimpleMessageModule.java @@ -42,13 +42,16 @@ import org.springframework.stereotype.Service; @Service public class SimpleMessageModule extends AbstractSpringModule implements ConfigOnOff { - public static final String SMS_ENABLED = "message.enabled"; - public static final String RESET_PASSWORD_ENABLED = "message.reset.password.enabled"; + private static final String SMS_ENABLED = "message.enabled"; + private static final String PROVIDER_ID = "message.provider.id"; + private static final String RESET_PASSWORD_ENABLED = "message.reset.password.enabled"; @Value("${message.enabled:false}") private boolean enabled; @Value("${message.reset.password.enabled:true}") private boolean resetPassword; + @Value("${message.provider:WebSMS}") + private String providerId; @Autowired @@ -66,11 +69,13 @@ public class SimpleMessageModule extends AbstractSpringModule implements ConfigO enabled = "true".equals(enabledObj); } - String resetPasswordEnabledObj = getStringPropertyValue(RESET_PASSWORD_ENABLED, true); - if(StringHelper.containsNonWhitespace(resetPasswordEnabledObj)) { - resetPassword = "true".equals(resetPasswordEnabledObj); + String resetEnabledObj = getStringPropertyValue(RESET_PASSWORD_ENABLED, true); + if(StringHelper.containsNonWhitespace(resetEnabledObj)) { + resetPassword = "true".equals(resetEnabledObj); } + providerId = getStringPropertyValue(PROVIDER_ID, providerId); + if(enabled) {//check enableSmsUserProperty(); } @@ -127,6 +132,12 @@ public class SimpleMessageModule extends AbstractSpringModule implements ConfigO setStringProperty(RESET_PASSWORD_ENABLED, Boolean.toString(resetPassword), true); } + public String getProviderId() { + return providerId == null ? null : providerId.toLowerCase(); + } - + public void setProviderId(String providerId) { + this.providerId = providerId; + setStringProperty(PROVIDER_ID, providerId, true); + } } diff --git a/src/main/java/org/olat/core/commons/services/sms/manager/SimpleMessageServiceImpl.java b/src/main/java/org/olat/core/commons/services/sms/manager/SimpleMessageServiceImpl.java index 32276f770052a812fae9b3cf33d98926b837e5ed..82592e2fc330695a4cea1ef04c788b2b3b62be2b 100644 --- a/src/main/java/org/olat/core/commons/services/sms/manager/SimpleMessageServiceImpl.java +++ b/src/main/java/org/olat/core/commons/services/sms/manager/SimpleMessageServiceImpl.java @@ -29,6 +29,10 @@ import org.olat.core.commons.services.sms.SimpleMessageException; import org.olat.core.commons.services.sms.SimpleMessageModule; import org.olat.core.commons.services.sms.SimpleMessageService; import org.olat.core.commons.services.sms.model.MessageStatistics; +import org.olat.core.commons.services.sms.ui.AbstractSMSConfigurationController; +import org.olat.core.gui.UserRequest; +import org.olat.core.gui.components.form.flexible.impl.Form; +import org.olat.core.gui.control.WindowControl; import org.olat.core.helpers.Settings; import org.olat.core.id.Identity; import org.olat.core.id.UserConstants; @@ -84,7 +88,7 @@ public class SimpleMessageServiceImpl implements SimpleMessageService { number = number.replace("+", "").replace(" ", ""); if(StringHelper.isLong(number)) { try { - Long phone = new Long(number); + Long phone = Long.valueOf(number); return phone > 0; } catch (NumberFormatException e) { // @@ -134,8 +138,15 @@ public class SimpleMessageServiceImpl implements SimpleMessageService { public MessagesSPI getMessagesSpi() { if(Settings.isDebuging()) return new DevNullProvider(); - if(messageModule.isEnabled() && messagesSpiList.size() > 0) { - return messagesSpiList.get(0); + if(messageModule.isEnabled() && !messagesSpiList.isEmpty()) { + String providerId = messageModule.getProviderId(); + if(StringHelper.containsNonWhitespace(providerId) && !"devnull".equals(providerId)) { + for(MessagesSPI spi:messagesSpiList) { + if(providerId.equalsIgnoreCase(spi.getId())) { + return spi; + } + } + } } return new DevNullProvider(); } @@ -157,6 +168,11 @@ public class SimpleMessageServiceImpl implements SimpleMessageService { return true; } + @Override + public AbstractSMSConfigurationController getConfigurationController(UserRequest ureq, WindowControl wControl, Form form) { + return null; + } + @Override public boolean send(String messageId, String text, String recipient) { log.info("Send: " + text); diff --git a/src/main/java/org/olat/core/commons/services/sms/spi/BulkSMSProvider.java b/src/main/java/org/olat/core/commons/services/sms/spi/BulkSMSProvider.java new file mode 100644 index 0000000000000000000000000000000000000000..fab8590a91d43dfd4a1f273243f4aea166707b5b --- /dev/null +++ b/src/main/java/org/olat/core/commons/services/sms/spi/BulkSMSProvider.java @@ -0,0 +1,166 @@ +/** + * <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.core.commons.services.sms.spi; + +import org.apache.http.HttpEntity; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.message.BasicHeader; +import org.apache.http.util.EntityUtils; +import org.json.JSONObject; +import org.olat.core.commons.services.sms.MessagesSPI; +import org.olat.core.commons.services.sms.SimpleMessageException; +import org.olat.core.commons.services.sms.ui.BulksSMSConfigurationController; +import org.olat.core.configuration.AbstractSpringModule; +import org.olat.core.gui.UserRequest; +import org.olat.core.gui.components.form.flexible.impl.Form; +import org.olat.core.gui.control.WindowControl; +import org.olat.core.logging.OLog; +import org.olat.core.logging.Tracing; +import org.olat.core.util.StringHelper; +import org.olat.core.util.coordinate.CoordinatorManager; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +/** + * + * Initial date: 4 mars 2019<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +@Service("messagesSpiBulkSMS") +public class BulkSMSProvider extends AbstractSpringModule implements MessagesSPI { + + private static final OLog log = Tracing.createLoggerFor(BulkSMSProvider.class); + + private static final String TOKEN_ID = "bulksms.token.id"; + private static final String TOKEN_SECRET = "bulksms.token.secret"; + + @Value("${websms.url:https://api.bulksms.com/v1/messages}") + private String url; + + @Value("${bulksms.token.id:}") + private String tokenId; + @Value("${bulksms.token.secret:}") + private String tokenSecret; + + @Autowired + public BulkSMSProvider(CoordinatorManager coordinatorManager) { + super(coordinatorManager); + } + + @Override + public void init() { + updateProperties(); + } + + @Override + protected void initFromChangedProperties() { + updateProperties(); + } + + private void updateProperties() { + tokenId = getStringPropertyValue(TOKEN_ID, tokenId); + tokenSecret = getStringPropertyValue(TOKEN_SECRET, tokenSecret); + } + + @Override + public String getId() { + return "bulksms"; + } + + @Override + public String getName() { + return "BulkSMS"; + } + + @Override + public boolean isValid() { + return StringHelper.containsNonWhitespace(tokenId) && StringHelper.containsNonWhitespace(tokenSecret); + } + + @Override + public BulksSMSConfigurationController getConfigurationController(UserRequest ureq, WindowControl wControl, Form form) { + return new BulksSMSConfigurationController(ureq, wControl, form); + } + + public String getTokenId() { + return tokenId; + } + + public void setTokenId(String tokenId) { + this.tokenId = tokenId; + setSecretStringProperty(TOKEN_ID, tokenId, true); + } + + public String getTokenSecret() { + return tokenSecret; + } + + public void setTokenSecret(String tokenSecret) { + this.tokenSecret = tokenSecret; + setSecretStringProperty(TOKEN_SECRET, tokenSecret, true); + } + + @Override + public boolean send(String messageId, String text, String recipient) + throws SimpleMessageException { + HttpPost send = new HttpPost(url + "?deduplication-id=" + messageId); + String token = StringHelper.encodeBase64(tokenId + ":" + tokenSecret); + send.setHeader(new BasicHeader("Authorization", "Basic " + token)); + send.setHeader(new BasicHeader("Content-Type", "application/json")); + try(CloseableHttpClient httpclient = HttpClientBuilder.create().build()) { + + String phone = recipient.replace("+", "").replace(" ", ""); + String objectStr = jsonPayload(text, phone); + HttpEntity smsEntity = new StringEntity(objectStr, ContentType.APPLICATION_JSON); + send.setEntity(smsEntity); + CloseableHttpResponse response = httpclient.execute(send); + int returnCode = response.getStatusLine().getStatusCode(); + String responseString = EntityUtils.toString(response.getEntity()); + if(returnCode == 200 || returnCode == 201) { + return true; + } + log.error("WebSMS return an error code " + returnCode + ": " + responseString); + return false; + } catch(Exception e) { + log.error("", e); + return false; + } + } + + private String jsonPayload(String text, String recipient) { + try { + JSONObject message = new JSONObject(); + message.put("body", text); + message.put("to", recipient); + message.put("encoding", "UNICODE"); + return message.toString(); + } catch (Exception e) { + log.error("", e); + return null; + } + } +} diff --git a/src/main/java/org/olat/core/commons/services/sms/spi/WebSMSProvider.java b/src/main/java/org/olat/core/commons/services/sms/spi/WebSMSProvider.java index 4c922d293140a7db04fa2aff21de2e31aa23315a..ec95344f69e4cc1541f6ddffafce2a14be6b59df 100644 --- a/src/main/java/org/olat/core/commons/services/sms/spi/WebSMSProvider.java +++ b/src/main/java/org/olat/core/commons/services/sms/spi/WebSMSProvider.java @@ -33,10 +33,16 @@ import org.apache.http.util.EntityUtils; import org.json.JSONArray; import org.json.JSONObject; import org.olat.core.commons.services.sms.MessagesSPI; +import org.olat.core.commons.services.sms.ui.WebSMSConfigurationController; +import org.olat.core.configuration.AbstractSpringModule; +import org.olat.core.gui.UserRequest; +import org.olat.core.gui.components.form.flexible.impl.Form; +import org.olat.core.gui.control.WindowControl; import org.olat.core.logging.OLog; import org.olat.core.logging.Tracing; import org.olat.core.util.StringHelper; -import org.springframework.beans.factory.InitializingBean; +import org.olat.core.util.coordinate.CoordinatorManager; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; @@ -48,11 +54,14 @@ import org.springframework.stereotype.Service; * */ @Service("messagesSpiWebSMS") -public class WebSMSProvider implements MessagesSPI, InitializingBean { +public class WebSMSProvider extends AbstractSpringModule implements MessagesSPI { private static final OLog log = Tracing.createLoggerFor(WebSMSProvider.class); private final BasicCredentialsProvider provider = new BasicCredentialsProvider(); + private static final String NAME = "websms.username"; + private static final String CREDENTIALS = "websms.password"; + @Value("${websms.url:https://api.websms.com/rest/smsmessaging/text}") private String url; @@ -63,6 +72,11 @@ public class WebSMSProvider implements MessagesSPI, InitializingBean { private boolean test = false; + @Autowired + public WebSMSProvider(CoordinatorManager coordinatorManager) { + super(coordinatorManager); + } + /** * Method means for unit tests. The changes are not persisted. * @@ -76,6 +90,24 @@ public class WebSMSProvider implements MessagesSPI, InitializingBean { new UsernamePasswordCredentials(username, password)); } + @Override + public void init() { + updateProperties(); + } + + @Override + protected void initFromChangedProperties() { + updateProperties(); + } + + private void updateProperties() { + username = getStringPropertyValue(NAME, username); + password = getStringPropertyValue(CREDENTIALS, password); + + provider.setCredentials(new AuthScope("api.websms.com", 443), + new UsernamePasswordCredentials(username, password)); + } + protected void setTest(boolean test) { this.test = test; } @@ -94,11 +126,28 @@ public class WebSMSProvider implements MessagesSPI, InitializingBean { public boolean isValid() { return StringHelper.containsNonWhitespace(username) && StringHelper.containsNonWhitespace(password); } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + setSecretStringProperty(NAME, username, true); + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + setSecretStringProperty(CREDENTIALS, password, true); + } @Override - public void afterPropertiesSet() throws Exception { - provider.setCredentials(new AuthScope("api.websms.com", 443), - new UsernamePasswordCredentials(username, password)); + public WebSMSConfigurationController getConfigurationController(UserRequest ureq, WindowControl wControl, Form form) { + return new WebSMSConfigurationController(ureq, wControl, form); } @Override @@ -109,7 +158,7 @@ public class WebSMSProvider implements MessagesSPI, InitializingBean { .build()) { String phone = recipient.replace("+", "").replace(" ", ""); - String objectStr = jsonPayload(messageId, text, new Long(phone)); + String objectStr = jsonPayload(messageId, text, Long.valueOf(phone)); HttpEntity smsEntity = new StringEntity(objectStr, ContentType.APPLICATION_JSON); send.setEntity(smsEntity); CloseableHttpResponse response = httpclient.execute(send); diff --git a/src/main/java/org/olat/core/commons/services/sms/ui/AbstractSMSConfigurationController.java b/src/main/java/org/olat/core/commons/services/sms/ui/AbstractSMSConfigurationController.java new file mode 100644 index 0000000000000000000000000000000000000000..03be3c2886670e188d240ca1c5a99fe29f907d66 --- /dev/null +++ b/src/main/java/org/olat/core/commons/services/sms/ui/AbstractSMSConfigurationController.java @@ -0,0 +1,48 @@ +/** + * <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.core.commons.services.sms.ui; + +import org.olat.core.gui.UserRequest; +import org.olat.core.gui.components.form.flexible.impl.Form; +import org.olat.core.gui.components.form.flexible.impl.FormBasicController; +import org.olat.core.gui.control.WindowControl; + +/** + * + * Initial date: 6 mars 2019<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public abstract class AbstractSMSConfigurationController extends FormBasicController { + + public AbstractSMSConfigurationController(UserRequest ureq, WindowControl wControl, Form form) { + super(ureq, wControl, LAYOUT_DEFAULT, null, form); + } + + @Override + protected boolean validateFormLogic(UserRequest ureq) { + return super.validateFormLogic(ureq); + } + + @Override + protected void formOK(UserRequest ureq) { + // + } +} diff --git a/src/main/java/org/olat/core/commons/services/sms/ui/BulksSMSConfigurationController.java b/src/main/java/org/olat/core/commons/services/sms/ui/BulksSMSConfigurationController.java new file mode 100644 index 0000000000000000000000000000000000000000..339eab961dce5116a8f8e9e0f70e5e8bff4629a5 --- /dev/null +++ b/src/main/java/org/olat/core/commons/services/sms/ui/BulksSMSConfigurationController.java @@ -0,0 +1,92 @@ +/** + * <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.core.commons.services.sms.ui; + +import org.olat.core.commons.services.sms.spi.BulkSMSProvider; +import org.olat.core.gui.UserRequest; +import org.olat.core.gui.components.form.flexible.FormItemContainer; +import org.olat.core.gui.components.form.flexible.elements.TextElement; +import org.olat.core.gui.components.form.flexible.impl.Form; +import org.olat.core.gui.control.Controller; +import org.olat.core.gui.control.WindowControl; +import org.olat.core.util.StringHelper; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * + * Initial date: 6 mars 2019<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class BulksSMSConfigurationController extends AbstractSMSConfigurationController { + + private TextElement tokenIdEl; + private TextElement tokenSecretEl; + + @Autowired + private BulkSMSProvider bulkSmsProvider; + + public BulksSMSConfigurationController(UserRequest ureq, WindowControl wControl, Form form) { + super(ureq, wControl, form); + + initForm(ureq); + } + + @Override + protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { + String tokenId = bulkSmsProvider.getTokenId(); + tokenIdEl = uifactory.addTextElement("bulksms.token.id", 128, tokenId, formLayout); + tokenIdEl.setMandatory(true); + + String tokenSecret = bulkSmsProvider.getTokenSecret(); + tokenSecretEl = uifactory.addTextElement("bulksms.token.secret", 128, tokenSecret, formLayout); + tokenSecretEl.setMandatory(true); + } + + @Override + protected void doDispose() { + // + } + + @Override + protected boolean validateFormLogic(UserRequest ureq) { + boolean allOk = super.validateFormLogic(ureq); + + tokenIdEl.clearError(); + if(!StringHelper.containsNonWhitespace(tokenIdEl.getValue())) { + tokenIdEl.setErrorKey("form.legende.mandatory", null); + allOk &= false; + } + + tokenSecretEl.clearError(); + if(!StringHelper.containsNonWhitespace(tokenSecretEl.getValue())) { + tokenSecretEl.setErrorKey("form.legende.mandatory", null); + allOk &= false; + } + + return allOk; + } + + @Override + protected void formOK(UserRequest ureq) { + bulkSmsProvider.setTokenId(tokenIdEl.getValue()); + bulkSmsProvider.setTokenSecret(tokenSecretEl.getValue()); + } +} diff --git a/src/main/java/org/olat/core/commons/services/sms/ui/SimpleMessageServiceAdminConfigurationController.java b/src/main/java/org/olat/core/commons/services/sms/ui/SimpleMessageServiceAdminConfigurationController.java index cd0545bbf92ea9f233aa9aa106c099b8cdcfa921..0bbd1269a05a4eddfc86a2034bd8714ba37f73f6 100644 --- a/src/main/java/org/olat/core/commons/services/sms/ui/SimpleMessageServiceAdminConfigurationController.java +++ b/src/main/java/org/olat/core/commons/services/sms/ui/SimpleMessageServiceAdminConfigurationController.java @@ -31,6 +31,7 @@ import org.olat.core.gui.components.form.flexible.elements.MultipleSelectionElem import org.olat.core.gui.components.form.flexible.elements.SingleSelection; 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.control.Controller; import org.olat.core.gui.control.WindowControl; import org.springframework.beans.factory.annotation.Autowired; @@ -49,39 +50,49 @@ public class SimpleMessageServiceAdminConfigurationController extends FormBasicC private MultipleSelectionElement enableEl; private MultipleSelectionElement resetPasswordEl; + private AbstractSMSConfigurationController providerConfigCtrl; + @Autowired private SimpleMessageModule messageModule; @Autowired private SimpleMessageService messagesService; public SimpleMessageServiceAdminConfigurationController(UserRequest ureq, WindowControl wControl) { - super(ureq, wControl); + super(ureq, wControl, "admin_configuration"); initForm(ureq); + updateEnableDisable(); + updateProviderConfiguration(ureq); } @Override protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { + FormLayoutContainer serviceCont = FormLayoutContainer.createDefaultFormLayout("service", getTranslator()); + formLayout.add(serviceCont); + setFormTitle("admin.configuration.title"); setFormDescription("admin.configuration.description"); String[] onValues = new String[]{ translate("on") }; - enableEl = uifactory.addCheckboxesHorizontal("enable", "admin.enable", formLayout, onKeys, onValues); + enableEl = uifactory.addCheckboxesHorizontal("enable", "admin.enable", serviceCont, onKeys, onValues); enableEl.addActionListener(FormEvent.ONCHANGE); if(messageModule.isEnabled()) { enableEl.select(onKeys[0], true); } List<MessagesSPI> spies = messagesService.getMessagesSpiList(); - String[] serviceKeys = new String[spies.size()]; - String[] serviceValues = new String[spies.size()]; + String[] serviceKeys = new String[spies.size() + 1]; + String[] serviceValues = new String[spies.size() + 1]; + serviceKeys[0] = "devnull"; + serviceValues[0] = translate("no.service.provider"); for(int i=spies.size(); i-->0; ) { - serviceKeys[i] = spies.get(i).getId(); - serviceValues[i] = spies.get(i).getName(); + serviceKeys[i + 1] = spies.get(i).getId(); + serviceValues[i + 1] = spies.get(i).getName(); } - serviceEl = uifactory.addDropdownSingleselect("service", "service", formLayout, serviceKeys, serviceValues, null); + serviceEl = uifactory.addDropdownSingleselect("service.providers", "service", serviceCont, serviceKeys, serviceValues, null); + serviceEl.addActionListener(FormEvent.ONCHANGE); if(messagesService.getMessagesSpi() != null) { - String activeServiceId = messagesService.getMessagesSpi().getId(); + String activeServiceId = messageModule.getProviderId(); for(int i=serviceKeys.length; i-->0; ) { if(serviceKeys[i].equals(activeServiceId)) { serviceEl.select(serviceKeys[i], true); @@ -90,12 +101,34 @@ public class SimpleMessageServiceAdminConfigurationController extends FormBasicC } String[] resetPasswordValues = new String[]{ translate("on.sms") }; - resetPasswordEl = uifactory.addCheckboxesHorizontal("reset.password", "reset.password", formLayout, onKeys, resetPasswordValues); - resetPasswordEl.addActionListener(FormEvent.ONCHANGE); + resetPasswordEl = uifactory.addCheckboxesHorizontal("reset.password", "reset.password", serviceCont, onKeys, resetPasswordValues); if(messageModule.isResetPasswordEnabled()) { resetPasswordEl.select(onKeys[0], true); } - updateEnableDisable(); + + FormLayoutContainer buttonCont = FormLayoutContainer.createButtonLayout("buttons", getTranslator()); + formLayout.add(buttonCont); + uifactory.addFormSubmitButton("save", buttonCont); + } + + private void updateProviderConfiguration(UserRequest ureq) { + removeControllerListener(providerConfigCtrl); + if(serviceEl.isOneSelected()) { + flc.remove("configuration"); + + String selectedProviderId = serviceEl.getSelectedKey(); + List<MessagesSPI> spies = messagesService.getMessagesSpiList(); + for(MessagesSPI spi:spies) { + if(spi.getId().equals(selectedProviderId)) { + providerConfigCtrl = spi.getConfigurationController(ureq, getWindowControl(), mainForm); + if(providerConfigCtrl != null) { + flc.add("configuration", providerConfigCtrl.getInitialFormItem()); + } + } + } + } else { + flc.remove("configuration"); + } } private void updateEnableDisable() { @@ -118,23 +151,32 @@ public class SimpleMessageServiceAdminConfigurationController extends FormBasicC // } + @Override + protected boolean validateFormLogic(UserRequest ureq) { + boolean allOk = super.validateFormLogic(ureq); + if(providerConfigCtrl != null) { + allOk &= providerConfigCtrl.validateFormLogic(ureq); + } + return allOk; + } + @Override protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) { if(enableEl == source) { updateEnableDisable(); - messageModule.setEnabled(enableEl.isAtLeastSelected(1)); - } else if(resetPasswordEl == source) { - messageModule.setResetPasswordEnabled(resetPasswordEl.isAtLeastSelected(1)); + } else if(serviceEl == source) { + updateProviderConfiguration(ureq); } super.formInnerEvent(ureq, source, event); } @Override protected void formOK(UserRequest ureq) { - // + messageModule.setEnabled(enableEl.isAtLeastSelected(1)); + messageModule.setResetPasswordEnabled(resetPasswordEl.isAtLeastSelected(1)); + messageModule.setProviderId(serviceEl.getSelectedKey()); + if(providerConfigCtrl != null) { + providerConfigCtrl.formOK(ureq); + } } - - - - } diff --git a/src/main/java/org/olat/core/commons/services/sms/ui/WebSMSConfigurationController.java b/src/main/java/org/olat/core/commons/services/sms/ui/WebSMSConfigurationController.java new file mode 100644 index 0000000000000000000000000000000000000000..4461a26d3d236e8546eb9f86ad057c78ee06710e --- /dev/null +++ b/src/main/java/org/olat/core/commons/services/sms/ui/WebSMSConfigurationController.java @@ -0,0 +1,110 @@ +/** + * <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.core.commons.services.sms.ui; + +import org.olat.core.commons.services.sms.spi.WebSMSProvider; +import org.olat.core.gui.UserRequest; +import org.olat.core.gui.components.form.flexible.FormItemContainer; +import org.olat.core.gui.components.form.flexible.elements.TextElement; +import org.olat.core.gui.components.form.flexible.impl.Form; +import org.olat.core.gui.control.Controller; +import org.olat.core.gui.control.WindowControl; +import org.olat.core.util.StringHelper; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * + * Initial date: 6 mars 2019<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class WebSMSConfigurationController extends AbstractSMSConfigurationController { + + private static final String PLACEHOLDER = "xxx-placeholder-xxx"; + + private TextElement usernameEl; + private TextElement passwordEl; + + private String replacedValue; + + @Autowired + private WebSMSProvider webSmsProvider; + + public WebSMSConfigurationController(UserRequest ureq, WindowControl wControl, Form form) { + super(ureq, wControl, form); + + initForm(ureq); + } + + @Override + protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { + String uname = webSmsProvider.getUsername(); + usernameEl = uifactory.addTextElement("websms.username", 128, uname, formLayout); + usernameEl.setMandatory(true); + + String creds = webSmsProvider.getPassword(); + if(StringHelper.containsNonWhitespace(creds)) { + replacedValue = creds; + creds = PLACEHOLDER; + } + passwordEl = uifactory.addPasswordElement("websms.password", "websms.password", 128, creds, formLayout); + passwordEl.setMandatory(true); + } + + @Override + protected void doDispose() { + // + } + + @Override + protected boolean validateFormLogic(UserRequest ureq) { + boolean allOk = super.validateFormLogic(ureq); + + usernameEl.clearError(); + if(!StringHelper.containsNonWhitespace(usernameEl.getValue())) { + usernameEl.setErrorKey("form.legende.mandatory", null); + allOk &= false; + } + + passwordEl.clearError(); + if(!StringHelper.containsNonWhitespace(passwordEl.getValue())) { + passwordEl.setErrorKey("form.legende.mandatory", null); + allOk &= false; + } else if(!PLACEHOLDER.equals(passwordEl.getValue())) { + replacedValue = passwordEl.getValue(); + passwordEl.setValue(PLACEHOLDER); + } + + return allOk; + } + + @Override + protected void formOK(UserRequest ureq) { + webSmsProvider.setUsername(usernameEl.getValue()); + + String credential = passwordEl.getValue(); + if(!PLACEHOLDER.equals(credential)) { + webSmsProvider.setPassword(credential); + passwordEl.setValue(PLACEHOLDER); + } else if(StringHelper.containsNonWhitespace(replacedValue)) { + webSmsProvider.setPassword(replacedValue); + } + } +} diff --git a/src/main/java/org/olat/core/commons/services/sms/ui/_content/admin_configuration.html b/src/main/java/org/olat/core/commons/services/sms/ui/_content/admin_configuration.html new file mode 100644 index 0000000000000000000000000000000000000000..383eddb54980366bcc2d531d1f26031b790c434a --- /dev/null +++ b/src/main/java/org/olat/core/commons/services/sms/ui/_content/admin_configuration.html @@ -0,0 +1,9 @@ +$r.render("service") +#if($r.available("configuration")) + $r.render("configuration") +#end +<div class="o_form form-horizontal"><div class="form-group clearfix"> + <div class="col-sm-offset-3 col-sm-9"> + $r.render("buttons") + </div> +</div></div> \ No newline at end of file diff --git a/src/main/java/org/olat/core/commons/services/sms/ui/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/core/commons/services/sms/ui/_i18n/LocalStrings_de.properties index d28faea964eb592a0c5a0d034d5365586802b028..1456b3a6f7e49dba88cd052bdab782d356a85d94 100644 --- a/src/main/java/org/olat/core/commons/services/sms/ui/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/core/commons/services/sms/ui/_i18n/LocalStrings_de.properties @@ -1,4 +1,4 @@ -#Tue Feb 07 13:58:37 CET 2017 +#Wed Mar 06 14:56:25 CET 2019 admin.configuration.description=<p>Die Benachrichtigung per SMS ist eine optionale Komponente.</p><p>Achtung\: durch das Versenden von SMS entstehen Kosten pro SMS\!</p> admin.configuration.title=SMS Konfiguration admin.enable=SMS Versand @@ -6,23 +6,28 @@ admin.menu.title=SMS admin.menu.title.alt=SMS Konfiguration udn Statistik admin.settings=SMS Dienst Konfiguration admin.statistics=SMS Versand +bulksms.token.id=Token ID +bulksms.token.secret=Token secret confirm.sms.phone=<h3>SMS Authentifizierung</h3><p>Das System erm\u00F6glicht eine Authentifizierung \u00FCber SMS, um ein verlorenes Passwort zur\u00FCcksetzen. Bitte geben Sie Ihre Mobile Telefonnummer an, um diesen Dienst zu aktivieren</p> dont.activate=Nicht aktivieren error.invalid.token=Token stimmt nicht\! error.phone.invalid=Das Nummer ist nicht valid (z.B. +41 12 345 67 89) +no.service.provider=Kein Provider angew\u00E4hlt on=ein on.sms=mit SMS Code -start.sms.authentication=SMS Authentifizierung starten reset.password=Password zur\u00FCcksetzen service=Dienst sms.phone.number=Telephon Mobil -sms.phone.number.hint=+41 12 345 67 89 sms.phone.number.example=Sie m\u00FCssen Ihre Telefonnummer im internationalen Format angeben (+41 12 345 67 89). +sms.phone.number.hint=+41 12 345 67 89 sms.send=SMS Authentifizierung starten sms.token=Ihr Token ist {0} sms.token.number=Token -sms.token.number.explain=Geben Sie den Best\u00E4tigungscode ein, den Sie per SMS erhalten haben. Falls Sie nach 1 Minute noch keine SMS erhalten haben, überprüfen Sie bitte, ob Sie das korrekte internationale Nummernformat verwendet haben. +sms.token.number.explain=Geben Sie den Best\u00E4tigungscode ein, den Sie per SMS erhalten haben. Falls Sie nach 1 Minute noch keine SMS erhalten haben, \u00FCberpr\u00FCfen Sie bitte, ob Sie das korrekte internationale Nummernformat verwendet haben. +start.sms.authentication=SMS Authentifizierung starten table.header.month=Monat table.header.numOfMessages=SMS table.header.year=Jahr warning.spi.not.configured=Dienst ist nicht konfiguriert +websms.password=Passwort +websms.username=Benutzername diff --git a/src/main/java/org/olat/core/commons/services/sms/ui/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/core/commons/services/sms/ui/_i18n/LocalStrings_en.properties index 6a610c4974761f4dff3d1f1e3e2356b99e760c3c..cd23e692896bae9b888630d74e3f02ae2609004a 100644 --- a/src/main/java/org/olat/core/commons/services/sms/ui/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/core/commons/services/sms/ui/_i18n/LocalStrings_en.properties @@ -1,4 +1,4 @@ -#Tue Feb 07 13:47:28 CET 2017 +#Wed Mar 06 14:56:12 CET 2019 admin.configuration.description=<p>Notification with SMS is an optional component.</p><p>Warning\: SMS costs occurred per SMS\!</p> admin.configuration.title=SMS configuration admin.enable=SMS distribution @@ -6,23 +6,28 @@ admin.menu.title=SMS admin.menu.title.alt=SMS configuration and statistics admin.settings=SMS service configuration admin.statistics=SMS distribution +bulksms.token.id=Token ID +bulksms.token.secret=Token secret confirm.sms.phone=<h3>SMS Authentication</h3><p>The system allows to authenticate via SMS to reset a lost password. Please enter your mobile phone number to activate this service.</p> dont.activate=Don't activate error.invalid.token=The code is not valid. error.phone.invalid=The number is not a valid phone number (e.g. +41 12 345 67 89) +no.service.provider=No provider selected on=on on.sms=with SMS code -start.sms.authentication=Start SMS Authentication reset.password=Reset password service=Service sms.phone.number=Mobile telefon -sms.phone.number.hint=+41 12 345 67 89 sms.phone.number.example=You need to enter your phone number in the international format (e.g. +41 12 345 67 89). +sms.phone.number.hint=+41 12 345 67 89 sms.send=Start authentication by SMS sms.token=Your token is {0} sms.token.number=Code sms.token.number.explain=Please enter the 6 digit number that you received by SMS. If you don't receive a SMS after 1 minute, please make sure you used the correct international number format. +start.sms.authentication=Start SMS Authentication table.header.month=Month table.header.numOfMessages=SMS table.header.year=Year warning.spi.not.configured=The service is not configured. +websms.password=Password +websms.username=User name diff --git a/src/main/java/org/olat/core/commons/services/sms/ui/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/core/commons/services/sms/ui/_i18n/LocalStrings_fr.properties index 9b4d9ce1116b46fec9754f6fcb7c557b03a78130..9e77b9391415978f323feeb9ad646af7d07962c2 100644 --- a/src/main/java/org/olat/core/commons/services/sms/ui/_i18n/LocalStrings_fr.properties +++ b/src/main/java/org/olat/core/commons/services/sms/ui/_i18n/LocalStrings_fr.properties @@ -1,4 +1,4 @@ -#Wed Mar 08 12:06:24 CET 2017 +#Wed Mar 06 14:57:26 CET 2019 admin.configuration.description=<p>La notifications par SMS est un composant optionnel.</p><p>Attention\: l'envoi de SMS occasione des co\u00FBts\!</p> admin.configuration.title=Configuration SMS admin.enable=Distribution SMS @@ -6,10 +6,13 @@ admin.menu.title=SMS admin.menu.title.alt=Configuration SMS et statistiques admin.settings=Configuration du service SMS admin.statistics=Distribution de SMS +bulksms.token.id=Token ID +bulksms.token.secret=Token secret confirm.sms.phone=<h3>Authentication par SMS</h3><p>Le syst\u00E8me permet de s'authentifier par SMS en cas d''oubli du mot de passe. Pour activer cette fonction, veuillez entrer votre num\u00E9ro de t\u00E9l\u00E9phone portable.</p> dont.activate=Ne pas activer error.invalid.token=Le code n'est pas valide. error.phone.invalid=Le num\u00E9ro n'est pas un num\u00E9ro de t\u00E9l\u00E9phone valide (par exemple +41 12 345 67 89) +no.service.provider=Aucun on=Activ\u00E9 on.sms=par code SMS reset.password=R\u00E9initialiser le mot de passe @@ -26,3 +29,5 @@ table.header.month=Mois table.header.numOfMessages=SMS table.header.year=Ann\u00E9e warning.spi.not.configured=Le service n'est pas configur\u00E9. +websms.password=Mot de passe +websms.username=Nom d'utilisateur diff --git a/src/main/java/org/olat/core/gui/components/form/flexible/impl/FormLayoutContainer.java b/src/main/java/org/olat/core/gui/components/form/flexible/impl/FormLayoutContainer.java index 48fc802af27aaa9ba0d3fefb628cf86ed1fb2e71..8dc829d078b748d5e0c2dc3a56a20ef1403d6d8c 100644 --- a/src/main/java/org/olat/core/gui/components/form/flexible/impl/FormLayoutContainer.java +++ b/src/main/java/org/olat/core/gui/components/form/flexible/impl/FormLayoutContainer.java @@ -297,9 +297,12 @@ public class FormLayoutContainer extends FormItemImpl implements FormItemContain * remove the component with the give name from this container * @param binderName */ + @Override public void remove(String formCompName) { FormItem toBeRemoved = getFormComponent(formCompName); - remove(formCompName, toBeRemoved); + if(toBeRemoved != null) { + remove(formCompName, toBeRemoved); + } } private void remove(String formCompName, FormItem toBeRemoved) { diff --git a/src/main/java/org/olat/modules/quality/analysis/ui/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/modules/quality/analysis/ui/_i18n/LocalStrings_fr.properties index 1d42a913667e63834f1b949e39bc63f1bb4eeb5e..207025e140fc7ef075a8214ef74ff3fb1b0aa90c 100644 --- a/src/main/java/org/olat/modules/quality/analysis/ui/_i18n/LocalStrings_fr.properties +++ b/src/main/java/org/olat/modules/quality/analysis/ui/_i18n/LocalStrings_fr.properties @@ -1,5 +1,6 @@ -#Thu Feb 28 14:56:33 CET 2019 +#Wed Mar 06 14:57:30 CET 2019 analysis.details=D\u00E9tails des tendances +analysis.details.print.title={0}\: {1} analysis.export=Exporter Excel analysis.pdf=Exporter au format PDF analysis.print=Imprimer diff --git a/src/main/java/org/olat/user/ui/role/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/user/ui/role/_i18n/LocalStrings_fr.properties index 51ae2c3a184f0c21d477ca4ce40ef95143419249..2a01ef809602c3732ca6bd3a892062701499778c 100644 --- a/src/main/java/org/olat/user/ui/role/_i18n/LocalStrings_fr.properties +++ b/src/main/java/org/olat/user/ui/role/_i18n/LocalStrings_fr.properties @@ -1,4 +1,4 @@ -#Thu Feb 28 14:58:47 CET 2019 +#Wed Mar 06 14:57:45 CET 2019 add.role=Ajouter un nouveau r\u00F4le admin.menu.title=R\u00F4le utilisateur \u00E0 utilisateur admin.menu.title.alt=R\u00F4le utilisateur \u00E0 utilisateur @@ -16,6 +16,7 @@ role.identifier=Identifiant role.name=R\u00F4le role.rights=Permissions table.header.id=ID +table.header.identifier=Identifiant table.header.managed=<i class\='o_icon o_icon_managed'> </i> table.header.role=R\u00F4le table.header.role.contra=R\u00F4le inverse