Author: sskracic Date: 2005-12-16 14:20:35 +0100 (Fri, 16 Dec 2005) New Revision: 1058 Added: contrib/ccm-ldn-camden-consultation/trunk/sql/ccm-ldn-camden-consultation/upgrade/oracle-se-1.0.3-1.1.0.sql contrib/ccm-ldn-camden-consultation/trunk/src/com/arsdigita/camden/cms/contenttypes/MobifiSMSProvider.java contrib/ccm-ldn-camden-consultation/trunk/src/com/arsdigita/camden/cms/contenttypes/SMSEmailProvider.java Modified: contrib/ccm-ldn-camden-consultation/trunk/application.xml contrib/ccm-ldn-camden-consultation/trunk/pdl/com/arsdigita/camden/cms/contenttypes/ConsultationAlert.pdl contrib/ccm-ldn-camden-consultation/trunk/src/ccm-ldn-camden-consultation.upgrade contrib/ccm-ldn-camden-consultation/trunk/src/com/arsdigita/camden/cms/contenttypes/ConsultationAlert.java contrib/ccm-ldn-camden-consultation/trunk/src/com/arsdigita/camden/cms/contenttypes/ConsultationConfig.java contrib/ccm-ldn-camden-consultation/trunk/src/com/arsdigita/camden/cms/contenttypes/ConsultationConfig_parameter.properties contrib/ccm-ldn-camden-consultation/trunk/src/com/arsdigita/camden/cms/contenttypes/ConsultationResources.properties contrib/ccm-ldn-camden-consultation/trunk/src/com/arsdigita/camden/cms/contenttypes/ui/ConsultationAlertForm.java Log: Started working on SMS notifications. Work in progress. Modified: contrib/ccm-ldn-camden-consultation/trunk/application.xml =================================================================== --- contrib/ccm-ldn-camden-consultation/trunk/application.xml 2005-12-15 20:07:37 UTC (rev 1057) +++ contrib/ccm-ldn-camden-consultation/trunk/application.xml 2005-12-16 13:20:35 UTC (rev 1058) @@ -3,7 +3,7 @@ name="ccm-ldn-camden-consultation" prettyName="Red Hat CCM Content Types" version="1.1.0" - release="1" + release="0" webapp="ROOT"> <ccm:dependencies> <ccm:requires name="ccm-core" version="6.1.1" relation="ge"/> Modified: contrib/ccm-ldn-camden-consultation/trunk/pdl/com/arsdigita/camden/cms/contenttypes/ConsultationAlert.pdl =================================================================== --- contrib/ccm-ldn-camden-consultation/trunk/pdl/com/arsdigita/camden/cms/contenttypes/ConsultationAlert.pdl 2005-12-15 20:07:37 UTC (rev 1057) +++ contrib/ccm-ldn-camden-consultation/trunk/pdl/com/arsdigita/camden/cms/contenttypes/ConsultationAlert.pdl 2005-12-16 13:20:35 UTC (rev 1058) @@ -29,6 +29,9 @@ String[1..1] confirmationToken = cam_consultation_alerts.confirmation_token VARCHAR(100); String[1..1] cancellationToken = cam_consultation_alerts.cancellation_token VARCHAR(100); Boolean[1..1] emailConfirmed = cam_consultation_alerts.email_confirmed; + String[0..1] mobileNumber = cam_consultation_alerts.mobile_number VARCHAR(100); + String[0..1] mobilePin = cam_consultation_alerts.mobile_pin VARCHAR(10); + Boolean[0..1] mobileConfirmed = cam_consultation_alerts.mobile_confirmed; reference key (cam_consultation_alerts.alert_id); } Added: contrib/ccm-ldn-camden-consultation/trunk/sql/ccm-ldn-camden-consultation/upgrade/oracle-se-1.0.3-1.1.0.sql =================================================================== --- contrib/ccm-ldn-camden-consultation/trunk/sql/ccm-ldn-camden-consultation/upgrade/oracle-se-1.0.3-1.1.0.sql 2005-12-15 20:07:37 UTC (rev 1057) +++ contrib/ccm-ldn-camden-consultation/trunk/sql/ccm-ldn-camden-consultation/upgrade/oracle-se-1.0.3-1.1.0.sql 2005-12-16 13:20:35 UTC (rev 1058) @@ -0,0 +1,7 @@ + +alter table cam_consultation_alerts add mobile_number VARCHAR(100); +alter table cam_consultation_alerts add mobile_pin VARCHAR(10); +alter table cam_consultation_alerts add mobile_confirmed CHAR(1); +alter table cam_consultation_alerts + add constraint cam_con_ale_mob_confir_c_3cz1u + check(mobile_confirmed in ('0', '1')); Property changes on: contrib/ccm-ldn-camden-consultation/trunk/sql/ccm-ldn-camden-consultation/upgrade/oracle-se-1.0.3-1.1.0.sql ___________________________________________________________________ Name: svn:keywords + Id Author URL Modified: contrib/ccm-ldn-camden-consultation/trunk/src/ccm-ldn-camden-consultation.upgrade =================================================================== --- contrib/ccm-ldn-camden-consultation/trunk/src/ccm-ldn-camden-consultation.upgrade 2005-12-15 20:07:37 UTC (rev 1057) +++ contrib/ccm-ldn-camden-consultation/trunk/src/ccm-ldn-camden-consultation.upgrade 2005-12-16 13:20:35 UTC (rev 1058) @@ -8,4 +8,7 @@ <version from="1.0.2" to="1.0.3"> <script sql="ccm-ldn-camden-consultation/upgrade/::database::-1.0.2-1.0.3.sql"/> </version> + <version from="1.0.3" to="1.1.0"> + <script sql="ccm-ldn-camden-consultation/upgrade/::database::-1.0.3-1.1.0.sql"/> + </version> </upgrade> Modified: contrib/ccm-ldn-camden-consultation/trunk/src/com/arsdigita/camden/cms/contenttypes/ConsultationAlert.java =================================================================== --- contrib/ccm-ldn-camden-consultation/trunk/src/com/arsdigita/camden/cms/contenttypes/ConsultationAlert.java 2005-12-15 20:07:37 UTC (rev 1057) +++ contrib/ccm-ldn-camden-consultation/trunk/src/com/arsdigita/camden/cms/contenttypes/ConsultationAlert.java 2005-12-16 13:20:35 UTC (rev 1058) @@ -1,17 +1,5 @@ package com.arsdigita.camden.cms.contenttypes; -import java.math.BigDecimal; -import java.security.GeneralSecurityException; -import java.util.Collection; -import java.util.Date; -import java.util.LinkedList; -import java.util.Locale; - -import javax.mail.MessagingException; - -import org.apache.commons.codec.binary.Base64; -import org.apache.log4j.Logger; - import com.arsdigita.cms.util.GlobalizationUtil; import com.arsdigita.domain.DataObjectNotFoundException; import com.arsdigita.globalization.GlobalizedMessage; @@ -32,6 +20,16 @@ import com.arsdigita.web.Web; import com.arsdigita.xml.Formatter; import com.arsdigita.xml.formatters.DateFormatter; +import java.math.BigDecimal; +import java.security.GeneralSecurityException; +import java.util.Collection; +import java.util.Date; +import java.util.LinkedList; +import java.util.Locale; +import java.util.Random; +import javax.mail.MessagingException; +import org.apache.commons.codec.binary.Base64; +import org.apache.log4j.Logger; /** * Alert requests for the Camden Consultation content type. @@ -56,6 +54,9 @@ public static final String CONFIRMATION_TOKEN = "confirmationToken"; public static final String CANCELLATION_TOKEN = "cancellationToken"; public static final String EMAIL_CONFIRMED = "emailConfirmed"; + public static final String MOBILE_NUMBER = "mobileNumber"; + public static final String MOBILE_PIN = "mobilePin"; + public static final String MOBILE_CONFIRMED = "mobileConfirmed"; public final static String CONFIRM_PATH = "/alert.jsp"; public final static String CONFIRM_PARAMETER = "co"; public final static String CANCEL_PARAMETER = "ca"; @@ -82,6 +83,7 @@ setConfirmationToken(getRandomString()); setCancellationToken(getRandomString()); setEmailConfirmed(Boolean.FALSE); + setMobileConfirmed(Boolean.FALSE); setCreationDate(new Date()); } @@ -149,6 +151,34 @@ set(EMAIL_CONFIRMED, value); } + public String getMobileNumber() { + return (String) get(MOBILE_NUMBER); + } + + public void setMobileNumber(String value) { + set(MOBILE_NUMBER, value); + } + + public String getMobilePin() { + return (String) get(MOBILE_PIN); + } + + public void randomizePin(int length) { + set(MOBILE_PIN, getRandomPin(length)); + } + + public void clearMobilePin() { + set(MOBILE_PIN, null); + } + + public Boolean getMobileConfirmed() { + return (Boolean) get(MOBILE_CONFIRMED); + } + + public void setMobileConfirmed(Boolean value) { + set(MOBILE_CONFIRMED, value); + } + private String getRandomString() { byte[] salt = new byte[8]; try { @@ -167,6 +197,21 @@ return result; } + private String getRandomPin(int length) { + StringBuffer pin = new StringBuffer(length); + Random random; + try { + random = Crypto.getRandom(); + } catch (GeneralSecurityException e) { + throw new RuntimeException(e); + } + for (int i=0; i<length; i++) { + pin.append(random.nextInt(10)); + } + return pin.toString(); + } + + public static String confirm(String token) { DataCollection alerts = SessionManager.getSession().retrieve(BASE_DATA_OBJECT_TYPE); Modified: contrib/ccm-ldn-camden-consultation/trunk/src/com/arsdigita/camden/cms/contenttypes/ConsultationConfig.java =================================================================== --- contrib/ccm-ldn-camden-consultation/trunk/src/com/arsdigita/camden/cms/contenttypes/ConsultationConfig.java 2005-12-15 20:07:37 UTC (rev 1057) +++ contrib/ccm-ldn-camden-consultation/trunk/src/com/arsdigita/camden/cms/contenttypes/ConsultationConfig.java 2005-12-16 13:20:35 UTC (rev 1058) @@ -22,6 +22,7 @@ import com.arsdigita.runtime.AbstractConfig; import com.arsdigita.util.parameter.Parameter; import com.arsdigita.util.parameter.StringParameter; +import com.arsdigita.util.parameter.SingletonParameter; /** * Defines the configuration parameters for the Camden Consultations @@ -40,11 +41,16 @@ "com.arsdigita.cms.camden.contenttypes.alerts_sender_email", Parameter.OPTIONAL, null); + private final Parameter m_smsProvider = new SingletonParameter + ("com.arsdigita.cms.camden.alerts_sms_provider", + Parameter.REQUIRED, new MobifiSMSProvider()); + private String m_adminEmail; public ConsultationConfig() { register(m_consultationsTermUrl); register(m_alertsSenderEmail); + register(m_smsProvider); loadInfo(); } @@ -67,4 +73,8 @@ return result; } + public SMSEmailProvider getSmsProvider() { + return (SMSEmailProvider) get(m_smsProvider); + } + } Modified: contrib/ccm-ldn-camden-consultation/trunk/src/com/arsdigita/camden/cms/contenttypes/ConsultationConfig_parameter.properties =================================================================== --- contrib/ccm-ldn-camden-consultation/trunk/src/com/arsdigita/camden/cms/contenttypes/ConsultationConfig_parameter.properties 2005-12-15 20:07:37 UTC (rev 1057) +++ contrib/ccm-ldn-camden-consultation/trunk/src/com/arsdigita/camden/cms/contenttypes/ConsultationConfig_parameter.properties 2005-12-16 13:20:35 UTC (rev 1058) @@ -1,8 +1,12 @@ -com.arsdigita.aplaws.consultations_term_url.title=The name of the Consultations Navigation Term -com.arsdigita.aplaws.consultations_term_url.purpose=Used to display the right category menu and path in the Consultations UI. -com.arsdigita.aplaws.consultations_term_url.example=Consultations -com.arsdigita.aplaws.consultations_term_url.format=[string] -com.arsdigita.aplaws.alerts_sender_email.title=The sender address for alert email -com.arsdigita.aplaws.alerts_sender_email.purpose=This email address will receive bounces and user requests. -com.arsdigita.aplaws.alerts_sender_email.example=bo...@ex... -com.arsdigita.aplaws.alerts_sender_email.format=[string] +com.arsdigita.cms.camden.consultations_term_url.title=The name of the Consultations Navigation Term +com.arsdigita.cms.camden.consultations_term_url.purpose=Used to display the right category menu and path in the Consultations UI. +com.arsdigita.cms.camden.consultations_term_url.example=Consultations +com.arsdigita.cms.camden.consultations_term_url.format=[string] +com.arsdigita.cms.camden.alerts_sender_email.title=The sender address for alert email +com.arsdigita.cms.camden.alerts_sender_email.purpose=This email address will receive bounces and user requests. +com.arsdigita.cms.camden.alerts_sender_email.example=bo...@ex... +com.arsdigita.cms.camden.alerts_sender_email.format=[string] +com.arsdigita.cms.camden.alerts_sms_provider.title=SMSEmailProvider implementation +com.arsdigita.cms.camden.alerts_sms_provider.purpose=A java class that implements the SMSEmailProvider interface +com.arsdigita.cms.camden.alerts_sms_provider.example=com.arsdigita.camden.cms.contenttypes.MobifiSMSProvider +com.arsdigita.cms.camden.alerts_sms_provider.format=[string] Modified: contrib/ccm-ldn-camden-consultation/trunk/src/com/arsdigita/camden/cms/contenttypes/ConsultationResources.properties =================================================================== --- contrib/ccm-ldn-camden-consultation/trunk/src/com/arsdigita/camden/cms/contenttypes/ConsultationResources.properties 2005-12-15 20:07:37 UTC (rev 1057) +++ contrib/ccm-ldn-camden-consultation/trunk/src/com/arsdigita/camden/cms/contenttypes/ConsultationResources.properties 2005-12-16 13:20:35 UTC (rev 1058) @@ -188,8 +188,12 @@ first_names=First Names last_name=Last Name email=Email +mobile=Mobile Number set_alert=Set Alert duplicate_alert=We already send alerts to the email address you entered. +invalid_mobile=The number does not represent a valid UK mobile number. +pin_verification=To verify your mobile number, enter the 4-digit PIN which should shortly \ +arrive to your mobile phone. confirm_token.invalid=\ <p>The URL contains a token for which we could not find \ Added: contrib/ccm-ldn-camden-consultation/trunk/src/com/arsdigita/camden/cms/contenttypes/MobifiSMSProvider.java =================================================================== --- contrib/ccm-ldn-camden-consultation/trunk/src/com/arsdigita/camden/cms/contenttypes/MobifiSMSProvider.java 2005-12-15 20:07:37 UTC (rev 1057) +++ contrib/ccm-ldn-camden-consultation/trunk/src/com/arsdigita/camden/cms/contenttypes/MobifiSMSProvider.java 2005-12-16 13:20:35 UTC (rev 1058) @@ -0,0 +1,22 @@ +package com.arsdigita.camden.cms.contenttypes; + +import com.arsdigita.util.Assert; + +public class MobifiSMSProvider implements SMSEmailProvider { + + public static final String UK_MOBILE_PREFIX = "447"; + + /** + * Provides the email address that will be used as gateway + * to the SMS for the supplied mobile number. + */ + public String getEmail(String mobileNumber) { + // trim everything that is not a digit + String trimmedNumber = mobileNumber.replaceAll("[^0-9]", ""); + Assert.truth(trimmedNumber.startsWith(UK_MOBILE_PREFIX), + "The number " + mobileNumber + " is not a UK mobile number"); + return trimmedNumber + "@sms.mobifi.com"; + } + +} + Property changes on: contrib/ccm-ldn-camden-consultation/trunk/src/com/arsdigita/camden/cms/contenttypes/MobifiSMSProvider.java ___________________________________________________________________ Name: svn:keywords + Id Author URL Added: contrib/ccm-ldn-camden-consultation/trunk/src/com/arsdigita/camden/cms/contenttypes/SMSEmailProvider.java =================================================================== --- contrib/ccm-ldn-camden-consultation/trunk/src/com/arsdigita/camden/cms/contenttypes/SMSEmailProvider.java 2005-12-15 20:07:37 UTC (rev 1057) +++ contrib/ccm-ldn-camden-consultation/trunk/src/com/arsdigita/camden/cms/contenttypes/SMSEmailProvider.java 2005-12-16 13:20:35 UTC (rev 1058) @@ -0,0 +1,11 @@ +package com.arsdigita.camden.cms.contenttypes; + +interface SMSEmailProvider { + + /** + * Provides the email address that will be used as gateway + * to the SMS for the supplied mobile number. + */ + String getEmail(String mobileNumber); + +} Property changes on: contrib/ccm-ldn-camden-consultation/trunk/src/com/arsdigita/camden/cms/contenttypes/SMSEmailProvider.java ___________________________________________________________________ Name: svn:keywords + Id Author URL Modified: contrib/ccm-ldn-camden-consultation/trunk/src/com/arsdigita/camden/cms/contenttypes/ui/ConsultationAlertForm.java =================================================================== --- contrib/ccm-ldn-camden-consultation/trunk/src/com/arsdigita/camden/cms/contenttypes/ui/ConsultationAlertForm.java 2005-12-15 20:07:37 UTC (rev 1057) +++ contrib/ccm-ldn-camden-consultation/trunk/src/com/arsdigita/camden/cms/contenttypes/ui/ConsultationAlertForm.java 2005-12-16 13:20:35 UTC (rev 1058) @@ -18,19 +18,19 @@ */ package com.arsdigita.camden.cms.contenttypes.ui; -import java.util.Date; - -import javax.mail.MessagingException; - import com.arsdigita.bebop.FormData; import com.arsdigita.bebop.FormProcessException; import com.arsdigita.bebop.Label; +import com.arsdigita.bebop.Page; import com.arsdigita.bebop.PageState; import com.arsdigita.bebop.event.FormProcessListener; import com.arsdigita.bebop.event.FormSectionEvent; import com.arsdigita.bebop.event.ParameterEvent; import com.arsdigita.bebop.event.ParameterListener; +import com.arsdigita.bebop.event.PrintEvent; +import com.arsdigita.bebop.event.PrintListener; import com.arsdigita.bebop.form.Submit; +import com.arsdigita.bebop.form.Widget; import com.arsdigita.bebop.parameters.EmailValidationListener; import com.arsdigita.bebop.parameters.ParameterData; import com.arsdigita.camden.cms.contenttypes.ConsultationAlert; @@ -44,6 +44,9 @@ import com.arsdigita.web.RedirectSignal; import com.arsdigita.web.URL; import com.arsdigita.web.Web; +import java.util.Date; +import java.util.TooManyListenersException; +import javax.mail.MessagingException; /** * <p>For for setting a new alert on the Camden Consultations @@ -60,36 +63,76 @@ public final static String FORM_NAME = "alert"; + private Name m_firstNames; + private Name m_lastName; + private Name m_email; + private Name m_mobile; + private Label m_pinLabel; + private Name m_pin; + + public ConsultationAlertForm() { this(FORM_NAME, ConsultationUtil.globalize("new_alert")); } public ConsultationAlertForm(String name, GlobalizedMessage heading) { - super(name, heading); - - addWidgets(); + this(name, new Label(heading)); } public ConsultationAlertForm(String name, Label heading) { super(name, heading); - addWidgets(); + try { + addWidgets(); + } catch (TooManyListenersException e) { + throw new RuntimeException(e); + } } - private void addWidgets() { - Name firstNames = + private void addWidgets() throws TooManyListenersException { + m_firstNames = new Name(ConsultationAlert.FIRST_NAMES, 100, false); - addField(ConsultationUtil.globalize("first_names"), firstNames); + addField(ConsultationUtil.globalize("first_names"), m_firstNames); - Name lastName = + m_firstNames.addPrintListener(new PrintListener() { + public void prepare(PrintEvent e) { + PageState state = e.getPageState(); + Widget widget = (Widget) e.getTarget(); + if (m_pin.isVisible(state)) { + widget.setReadOnly(); + } + } + }); + + m_lastName = new Name(ConsultationAlert.LAST_NAME, 100, false); - addField(ConsultationUtil.globalize("last_name"), lastName); + addField(ConsultationUtil.globalize("last_name"), m_lastName); - Name email = + m_lastName.addPrintListener(new PrintListener() { + public void prepare(PrintEvent e) { + PageState state = e.getPageState(); + Widget widget = (Widget) e.getTarget(); + if (m_pin.isVisible(state)) { + widget.setReadOnly(); + } + } + }); + + m_email = new Name(ConsultationAlert.EMAIL, 100, false); - email.addValidationListener(new ParameterListener() { + m_email.addPrintListener(new PrintListener() { + public void prepare(PrintEvent e) { + PageState state = e.getPageState(); + Widget widget = (Widget) e.getTarget(); + if (m_pin.isVisible(state)) { + widget.setReadOnly(); + } + } + }); + m_email.addValidationListener(new ParameterListener() { + private EmailValidationListener m_emailValidation = new EmailValidationListener(); @@ -113,6 +156,7 @@ alerts.addEqualsFilter(ConsultationAlert.EMAIL_CONFIRMED, Boolean.TRUE); if (alerts.next()) { + alerts.close(); data.invalidate(); data.addError((String)ConsultationUtil. globalize("duplicate_alert").localize()); @@ -120,14 +164,66 @@ } }); - addField(ConsultationUtil.globalize("email"), email); + addField(ConsultationUtil.globalize("email"), m_email); + m_mobile = + new Name(ConsultationAlert.MOBILE_NUMBER, 100, false); + m_mobile.addValidationListener(new ParameterListener() { + public void validate(ParameterEvent e) throws FormProcessException { + PageState state = e.getPageState(); + ParameterData data = e.getParameterData(); + if (isCancelled(state)) { + return; + } + if (data == null || data.getValue().toString().trim().length() == 0) { + return; + } + // strip everything but digits + String number = data.getValue().toString().replaceAll("[^0-9]", ""); + // number is valid if it starts with 447 or 07 or 7 + // First strip the leading country prefix, if exists + number = number.replaceFirst("^44", ""); + // then strip the leading zero + number = number.replaceFirst("^0", ""); + // We now have to have a number starting with 7 to denote UK mobile network. + // It must be at least (or exactly?) 10 digits in length + // 7789 xxx xxx + if (!number.startsWith("7") || number.length() < 10) { + data.addError((String)ConsultationUtil. + globalize("invalid_mobile").localize()); + } else { + data.setValue("+44" + number); + } + } + }); + addField(ConsultationUtil.globalize("mobile"), m_mobile); + + m_mobile.addPrintListener(new PrintListener() { + public void prepare(PrintEvent e) { + PageState state = e.getPageState(); + Widget widget = (Widget) e.getTarget(); + if (m_pin.isVisible(state)) { + widget.setReadOnly(); + } + } + }); + + m_pinLabel = new Label(ConsultationUtil.globalize("pin_confirmation")); + m_pin = new Name(ConsultationAlert.MOBILE_PIN, 10, false); + addField(m_pinLabel, m_pin); + addAction(new Submit(ConsultationUtil.globalize("set_alert"))); addAction(new Cancel()); addProcessListener(this); } + public void register(Page p) { + super.register(p); + p.setVisibleDefault(m_pinLabel, false); + p.setVisibleDefault(m_pin, false); + } + public void process(FormSectionEvent event) throws FormProcessException { FormData data = event.getFormData(); PageState state = event.getPageState(); @@ -164,6 +260,34 @@ alert.setFirstNames(data.getString(ConsultationAlert.FIRST_NAMES)); alert.setLastName(data.getString(ConsultationAlert.LAST_NAME)); alert.setEmail(email); + String mobile = data.getString(ConsultationAlert.MOBILE_NUMBER); + if (m_pin.isVisible(state)) { + // Validate PIN here. + String storedPin = alert.getMobilePin(); + if (storedPin == null) { + throw new FormProcessException("PIN not generated."); + } + if (!storedPin.equals(data.getString(ConsultationAlert.MOBILE_PIN))) { + throw new FormProcessException("PIN mismatch."); + } + alert.setMobileConfirmed(Boolean.TRUE); + } else { + if (mobile != null && mobile.trim().length() > 0) { + alert.setMobileNumber(mobile); + alert.randomizePin(4); + alert.save(); + m_pinLabel.setVisible(state, true); + m_pin.setVisible(state, true); + fireInit(event); + return; + } else { + // clear the mobile number that might have been submitted previously + alert.setMobileNumber(null); + alert.clearMobilePin(); + alert.setMobileConfirmed(Boolean.FALSE); + } + } + alert.save(); String from = |