← Back to team overview

dhis2-devs team mailing list archive

[Merge] lp:~halvdanhg/dhis2/test-email into lp:dhis2

 

Halvdan Hoem Grelland has proposed merging lp:~halvdanhg/dhis2/test-email into lp:dhis2.

Commit message:
Implemented blueprint test-email. Added barebones EmailService and new api endpoint email/sendTestEmail

Requested reviews:
  Lars Helge Øverland (larshelge)

For more details, see:
https://code.launchpad.net/~halvdanhg/dhis2/test-email/+merge/223380

Implements blueprint 'test-email': https://blueprints.launchpad.net/dhis2/+spec/test-email

Notable:
- The existing email API is abstracted as a MessageService wherein the mode of delivery (i.e. internal message, email, sms) for the message is not directly selectable. Using the MessageService was therefore not a very good solution.
- An EmailService has been implemented instead on top of EmailMessageSender. For now it only implements sendEmail(~) and sendTestEmail(), but could be extended to provide more general email related features (configuration etc.) if need be.
- A new API endpoint has been created at api/email/sendTestEmail which sends an automatically generated test message to the current user upon a POST-request. The reply string informs of the success or failure (missing settings) of the request.

Small remark:
Implementation and testing took a loot more time than it should have due to the default spring async executor (SimpleAsyncTaskExecutor) which is used by EmailMessageSender silently ignoring exceptions. This is still the case and could still cause inexplicable and undebuggable problems when sending emails.

Test by going to /dhis-web-maintenance-settings/systemEmailSettings.action and click the link "send me a test email"
-- 
https://code.launchpad.net/~halvdanhg/dhis2/test-email/+merge/223380
Your team DHIS 2 developers is subscribed to branch lp:dhis2.
=== added directory 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/email'
=== added file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/email/EmailService.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/email/EmailService.java	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/email/EmailService.java	2014-06-17 10:19:35 +0000
@@ -0,0 +1,73 @@
+package org.hisp.dhis.email;
+
+/*
+ * Copyright (c) 2004-2014, University of Oslo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * Neither the name of the HISP project nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+import org.hisp.dhis.user.User;
+
+import java.util.Set;
+
+/**
+ * @author Halvdan Hoem Grelland <halvdanhg@xxxxxxxxx>
+ */
+public interface EmailService
+{
+    /**
+     * Checks whether email is configured for the system or not.
+     * @return true if all necessary email configurations are set.
+     */
+    boolean emailEnabled();
+
+    /**
+     * Sends an email to the recipient user from the sender.
+     *
+     * @param subject the subject text of the email.
+     * @param text the text (body) of the email.
+     * @param sender the sender of the email.
+     * @param recipient the recipient of the email.
+     * @param forceSend if true the email is sent regardless of the recipients' email notification settings.
+     */
+    void sendEmail( String subject, String text, User sender, User recipient, boolean forceSend );
+
+    /**
+     * Sends an email to multiple recipients from the sender.
+     *
+     * @param subject the subject text of the email.
+     * @param text the text (body) of the email.
+     * @param sender the sender of the email.
+     * @param recipients the recipients of the email.
+     * @param forceSend if true the email is sent regardless of the email notification settings of the recipients.
+     */
+    void sendEmail( String subject, String text, User sender, Set<User> recipients, boolean forceSend);
+
+    /**
+     * Sends an automatically generated email message to the current user.
+     * Useful for testing the SMTP configuration of the system.
+     */
+    void sendTestEmail( );
+}

=== added directory 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/email'
=== added file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/email/DefaultEmailService.java'
--- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/email/DefaultEmailService.java	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/email/DefaultEmailService.java	2014-06-17 10:19:35 +0000
@@ -0,0 +1,111 @@
+package org.hisp.dhis.email;
+
+/*
+ * Copyright (c) 2004-2014, University of Oslo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * Neither the name of the HISP project nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hisp.dhis.message.MessageSender;
+import org.hisp.dhis.setting.SystemSettingManager;
+import org.hisp.dhis.user.CurrentUserService;
+import org.hisp.dhis.user.User;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * @author Halvdan Hoem Grelland <halvdanhg@xxxxxxxxx>
+ */
+@Transactional
+public class DefaultEmailService
+    implements EmailService
+{
+    private static final Log log = LogFactory.getLog( DefaultEmailService.class );
+
+    private static final String TEST_EMAIL_SUBJECT = "Test email from DHIS 2";
+    private static final String TEST_EMAIL_TEXT = "This is an automatically generated email from ";
+
+    // -------------------------------------------------------------------------
+    // Dependencies
+    // -------------------------------------------------------------------------
+
+    private MessageSender emailMessageSender;
+
+    public void setEmailMessageSender(MessageSender emailMessageSender)
+    {
+        this.emailMessageSender = emailMessageSender;
+    }
+
+    private CurrentUserService currentUserService;
+
+    public void setCurrentUserService( CurrentUserService currentUserService )
+    {
+        this.currentUserService = currentUserService;
+    }
+
+    private SystemSettingManager systemSettingManager;
+
+    public void setSystemSettingManager( SystemSettingManager systemSettingManager )
+    {
+        this.systemSettingManager = systemSettingManager;
+    }
+
+    // -------------------------------------------------------------------------
+    // EmailService implementation
+    // -------------------------------------------------------------------------
+
+    @Override
+    public boolean emailEnabled()
+    {
+        return systemSettingManager.emailEnabled();
+    }
+
+    @Override
+    public void sendEmail( String subject, String text, User sender, User recipient, boolean forceSend )
+    {
+        Set<User> recipients = new HashSet<User>( );
+        recipients.add( recipient );
+
+        /* Method is called asynchronously, must therefore re-instantiate HashSet in method call */
+        emailMessageSender.sendMessage( subject, text, sender, new HashSet<User>( recipients ), forceSend );
+    }
+
+    @Override
+    public void sendEmail( String subject, String text, User sender, Set<User> recipients, boolean forceSend )
+    {
+        emailMessageSender.sendMessage( subject, text, sender, new HashSet<User>( recipients ), forceSend );
+    }
+
+    @Override
+    public void sendTestEmail( )
+    {
+        String instanceName = systemSettingManager.getSystemSetting( systemSettingManager.KEY_APPLICATION_TITLE ).toString();
+        sendEmail( TEST_EMAIL_SUBJECT, TEST_EMAIL_TEXT + instanceName, null, currentUserService.getCurrentUser(), true );
+    }
+}

=== modified file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/message/EmailMessageSender.java'
--- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/message/EmailMessageSender.java	2014-05-20 15:16:46 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/message/EmailMessageSender.java	2014-06-17 10:19:35 +0000
@@ -86,7 +86,7 @@
     @Async
     @Override
     public String sendMessage( String subject, String text, User sender, Set<User> users, boolean forceSend )
-    {        
+    {
         String hostName = systemSettingManager.getEmailHostName();
         int port = systemSettingManager.getEmailPort();
         String username = systemSettingManager.getEmailUsername();
@@ -132,7 +132,6 @@
             if ( hasRecipients )
             {
                 email.send();
-                
                 log.info( "Email sent using host: " + hostName + " with TLS: " + tls );
             }
         }
@@ -140,7 +139,7 @@
         {
             log.warn( "Could not send email: " + ex.getMessage() );
         }
-        
+
         return null;
     }
 
@@ -151,7 +150,7 @@
         email.setHostName( hostName );
         email.setFrom( defaultIfEmpty( sender, FROM_ADDRESS ), FROM_NAME );
         email.setSmtpPort( port );
-        email.setTLS( true );
+        email.setTLS( tls );
         
         if ( username != null && password != null )
         {

=== modified file 'dhis-2/dhis-services/dhis-service-core/src/main/resources/META-INF/dhis/beans.xml'
--- dhis-2/dhis-services/dhis-service-core/src/main/resources/META-INF/dhis/beans.xml	2014-06-16 09:50:27 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/resources/META-INF/dhis/beans.xml	2014-06-17 10:19:35 +0000
@@ -637,6 +637,12 @@
     <property name="userService" ref="org.hisp.dhis.user.UserService" />
   </bean>
 
+  <bean id="org.hisp.dhis.email.EmailService" class="org.hisp.dhis.email.DefaultEmailService">
+    <property name="emailMessageSender" ref="emailMessageSender" />
+    <property name="currentUserService" ref="org.hisp.dhis.user.CurrentUserService" />
+    <property name="systemSettingManager" ref="org.hisp.dhis.setting.SystemSettingManager" />
+  </bean>
+
   <bean id="org.hisp.dhis.concept.ConceptService" class="org.hisp.dhis.concept.DefaultConceptService">
     <property name="conceptStore" ref="org.hisp.dhis.concept.ConceptStore" />
   </bean>

=== added file 'dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/EmailController.java'
--- dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/EmailController.java	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/EmailController.java	2014-06-17 10:19:35 +0000
@@ -0,0 +1,94 @@
+package org.hisp.dhis.webapi.controller;
+
+/*
+ * Copyright (c) 2004-2014, University of Oslo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * Neither the name of the HISP project nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hisp.dhis.email.EmailService;
+import org.hisp.dhis.user.CurrentUserService;
+import org.hisp.dhis.webapi.utils.ContextUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * @author Halvdan Hoem Grelland <halvdanhg@xxxxxxxxx>
+ */
+@Controller
+@RequestMapping( value = EmailController.RESOURCE_PATH )
+public class EmailController
+{
+    private static final Log log = LogFactory.getLog( EmailController.class );
+
+    public static final String RESOURCE_PATH = "/email";
+
+    //--------------------------------------------------------------------------
+    // Dependencies
+    //--------------------------------------------------------------------------
+
+    @Autowired
+    private EmailService emailService;
+
+    @Autowired
+    private CurrentUserService currentUserService;
+
+    @RequestMapping( value = "/sendTestEmail" , method = RequestMethod.POST, produces = ContextUtils.CONTENT_TYPE_TEXT )
+    public @ResponseBody String sendTestEmail( HttpServletRequest request, HttpServletResponse response )
+    {
+        String responseMessage;
+        String userEmail = currentUserService.getCurrentUser().getEmail();
+        boolean smtpConfigured = emailService.emailEnabled();
+        boolean userEmailConfigured = userEmail != null && !userEmail.isEmpty();
+
+        if( smtpConfigured && userEmailConfigured )
+        {
+            response.setStatus( HttpServletResponse.SC_OK );
+            emailService.sendTestEmail( );
+
+            responseMessage =  "A test email was sent to " + userEmail;
+        }
+        else if( userEmailConfigured )
+        {
+            response.setStatus( HttpServletResponse.SC_ACCEPTED );
+            responseMessage = "Could not send test email to " + userEmail + ": SMTP is not configured";
+        }
+        else /* smtpConfigured */
+        {
+            response.setStatus( HttpServletResponse.SC_ACCEPTED );
+            responseMessage = "Could not send test email: no user email address configured";
+        }
+
+        return responseMessage;
+    }
+}

=== modified file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-settings/src/main/webapp/dhis-web-maintenance-settings/systemEmailSettings.vm'
--- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-settings/src/main/webapp/dhis-web-maintenance-settings/systemEmailSettings.vm	2014-05-20 15:16:46 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-settings/src/main/webapp/dhis-web-maintenance-settings/systemEmailSettings.vm	2014-06-17 10:19:35 +0000
@@ -15,8 +15,17 @@
 			});
 		});
 		
-		jQuery( '#smtpHostName' ).blur();
+    jQuery( '#smtpHostName' ).blur();
+
+    jQuery( "#sendTestEmail" ).click( function ( e ){
+        e.preventDefault();
+        jQuery.post( '/api/email/sendTestEmail',
+        function( reply ) {
+          setHeaderDelayMessage ( reply );
+        });
+    });
 	});
+
 </script>
 
 <h3>$i18n.getString( "smtp_settings" ) #openHelp( "systemEmailSettings" )</h3>
@@ -54,6 +63,11 @@
 
 <div class="setting"><input type="text" id="emailSender" name="emailSender" value="$!emailSender" autocomplete="off" placeholder="noreply&#64;dhis2.org"></div>
 
-<div class="setting"><input type="button" value="$i18n.getString( 'save' )" style="width:10em"></div>
+<div class="setting">
+  <input type="button" value="$i18n.getString( 'save' )" style="width:10em">
+  <span style="margin-left: 1em;"><a id="sendTestEmail" href="send-test-email" title="Send an automatically generated email using the supplied SMTP settings to your email address">Send me a test email</a></span>
+</div>
 
 </form>
+
+


Follow ups