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

Proposed by Halvdan Hoem Grelland
Status: Merged
Merged at revision: 15774
Proposed branch: lp:~halvdanhg/dhis2/test-email
Merge into: lp:dhis2
Diff against target: 386 lines (+303/-6)
6 files modified
dhis-2/dhis-api/src/main/java/org/hisp/dhis/email/EmailService.java (+73/-0)
dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/email/DefaultEmailService.java (+111/-0)
dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/message/EmailMessageSender.java (+3/-4)
dhis-2/dhis-services/dhis-service-core/src/main/resources/META-INF/dhis/beans.xml (+6/-0)
dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/EmailController.java (+94/-0)
dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-settings/src/main/webapp/dhis-web-maintenance-settings/systemEmailSettings.vm (+16/-2)
To merge this branch: bzr merge lp:~halvdanhg/dhis2/test-email
Reviewer Review Type Date Requested Status
Lars Helge Øverland Pending
Review via email: mp+223380@code.launchpad.net

Commit message

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

Description of the change

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"

To post a comment you must log in.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== 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 @@
1package org.hisp.dhis.email;
2
3/*
4 * Copyright (c) 2004-2014, University of Oslo
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 * Redistributions of source code must retain the above copyright notice, this
10 * list of conditions and the following disclaimer.
11 *
12 * Redistributions in binary form must reproduce the above copyright notice,
13 * this list of conditions and the following disclaimer in the documentation
14 * and/or other materials provided with the distribution.
15 * Neither the name of the HISP project nor the names of its contributors may
16 * be used to endorse or promote products derived from this software without
17 * specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
23 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
26 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31import org.hisp.dhis.user.User;
32
33import java.util.Set;
34
35/**
36 * @author Halvdan Hoem Grelland <halvdanhg@gmail.com>
37 */
38public interface EmailService
39{
40 /**
41 * Checks whether email is configured for the system or not.
42 * @return true if all necessary email configurations are set.
43 */
44 boolean emailEnabled();
45
46 /**
47 * Sends an email to the recipient user from the sender.
48 *
49 * @param subject the subject text of the email.
50 * @param text the text (body) of the email.
51 * @param sender the sender of the email.
52 * @param recipient the recipient of the email.
53 * @param forceSend if true the email is sent regardless of the recipients' email notification settings.
54 */
55 void sendEmail( String subject, String text, User sender, User recipient, boolean forceSend );
56
57 /**
58 * Sends an email to multiple recipients from the sender.
59 *
60 * @param subject the subject text of the email.
61 * @param text the text (body) of the email.
62 * @param sender the sender of the email.
63 * @param recipients the recipients of the email.
64 * @param forceSend if true the email is sent regardless of the email notification settings of the recipients.
65 */
66 void sendEmail( String subject, String text, User sender, Set<User> recipients, boolean forceSend);
67
68 /**
69 * Sends an automatically generated email message to the current user.
70 * Useful for testing the SMTP configuration of the system.
71 */
72 void sendTestEmail( );
73}
074
=== 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 @@
1package org.hisp.dhis.email;
2
3/*
4 * Copyright (c) 2004-2014, University of Oslo
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 * Redistributions of source code must retain the above copyright notice, this
10 * list of conditions and the following disclaimer.
11 *
12 * Redistributions in binary form must reproduce the above copyright notice,
13 * this list of conditions and the following disclaimer in the documentation
14 * and/or other materials provided with the distribution.
15 * Neither the name of the HISP project nor the names of its contributors may
16 * be used to endorse or promote products derived from this software without
17 * specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
23 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
26 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31import org.apache.commons.logging.Log;
32import org.apache.commons.logging.LogFactory;
33import org.hisp.dhis.message.MessageSender;
34import org.hisp.dhis.setting.SystemSettingManager;
35import org.hisp.dhis.user.CurrentUserService;
36import org.hisp.dhis.user.User;
37import org.springframework.transaction.annotation.Transactional;
38
39import java.util.HashSet;
40import java.util.Set;
41
42/**
43 * @author Halvdan Hoem Grelland <halvdanhg@gmail.com>
44 */
45@Transactional
46public class DefaultEmailService
47 implements EmailService
48{
49 private static final Log log = LogFactory.getLog( DefaultEmailService.class );
50
51 private static final String TEST_EMAIL_SUBJECT = "Test email from DHIS 2";
52 private static final String TEST_EMAIL_TEXT = "This is an automatically generated email from ";
53
54 // -------------------------------------------------------------------------
55 // Dependencies
56 // -------------------------------------------------------------------------
57
58 private MessageSender emailMessageSender;
59
60 public void setEmailMessageSender(MessageSender emailMessageSender)
61 {
62 this.emailMessageSender = emailMessageSender;
63 }
64
65 private CurrentUserService currentUserService;
66
67 public void setCurrentUserService( CurrentUserService currentUserService )
68 {
69 this.currentUserService = currentUserService;
70 }
71
72 private SystemSettingManager systemSettingManager;
73
74 public void setSystemSettingManager( SystemSettingManager systemSettingManager )
75 {
76 this.systemSettingManager = systemSettingManager;
77 }
78
79 // -------------------------------------------------------------------------
80 // EmailService implementation
81 // -------------------------------------------------------------------------
82
83 @Override
84 public boolean emailEnabled()
85 {
86 return systemSettingManager.emailEnabled();
87 }
88
89 @Override
90 public void sendEmail( String subject, String text, User sender, User recipient, boolean forceSend )
91 {
92 Set<User> recipients = new HashSet<User>( );
93 recipients.add( recipient );
94
95 /* Method is called asynchronously, must therefore re-instantiate HashSet in method call */
96 emailMessageSender.sendMessage( subject, text, sender, new HashSet<User>( recipients ), forceSend );
97 }
98
99 @Override
100 public void sendEmail( String subject, String text, User sender, Set<User> recipients, boolean forceSend )
101 {
102 emailMessageSender.sendMessage( subject, text, sender, new HashSet<User>( recipients ), forceSend );
103 }
104
105 @Override
106 public void sendTestEmail( )
107 {
108 String instanceName = systemSettingManager.getSystemSetting( systemSettingManager.KEY_APPLICATION_TITLE ).toString();
109 sendEmail( TEST_EMAIL_SUBJECT, TEST_EMAIL_TEXT + instanceName, null, currentUserService.getCurrentUser(), true );
110 }
111}
0112
=== 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 @@
86 @Async86 @Async
87 @Override87 @Override
88 public String sendMessage( String subject, String text, User sender, Set<User> users, boolean forceSend )88 public String sendMessage( String subject, String text, User sender, Set<User> users, boolean forceSend )
89 { 89 {
90 String hostName = systemSettingManager.getEmailHostName();90 String hostName = systemSettingManager.getEmailHostName();
91 int port = systemSettingManager.getEmailPort();91 int port = systemSettingManager.getEmailPort();
92 String username = systemSettingManager.getEmailUsername();92 String username = systemSettingManager.getEmailUsername();
@@ -132,7 +132,6 @@
132 if ( hasRecipients )132 if ( hasRecipients )
133 {133 {
134 email.send();134 email.send();
135
136 log.info( "Email sent using host: " + hostName + " with TLS: " + tls );135 log.info( "Email sent using host: " + hostName + " with TLS: " + tls );
137 }136 }
138 }137 }
@@ -140,7 +139,7 @@
140 {139 {
141 log.warn( "Could not send email: " + ex.getMessage() );140 log.warn( "Could not send email: " + ex.getMessage() );
142 }141 }
143 142
144 return null;143 return null;
145 }144 }
146145
@@ -151,7 +150,7 @@
151 email.setHostName( hostName );150 email.setHostName( hostName );
152 email.setFrom( defaultIfEmpty( sender, FROM_ADDRESS ), FROM_NAME );151 email.setFrom( defaultIfEmpty( sender, FROM_ADDRESS ), FROM_NAME );
153 email.setSmtpPort( port );152 email.setSmtpPort( port );
154 email.setTLS( true );153 email.setTLS( tls );
155 154
156 if ( username != null && password != null )155 if ( username != null && password != null )
157 {156 {
158157
=== 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 @@
637 <property name="userService" ref="org.hisp.dhis.user.UserService" />637 <property name="userService" ref="org.hisp.dhis.user.UserService" />
638 </bean>638 </bean>
639639
640 <bean id="org.hisp.dhis.email.EmailService" class="org.hisp.dhis.email.DefaultEmailService">
641 <property name="emailMessageSender" ref="emailMessageSender" />
642 <property name="currentUserService" ref="org.hisp.dhis.user.CurrentUserService" />
643 <property name="systemSettingManager" ref="org.hisp.dhis.setting.SystemSettingManager" />
644 </bean>
645
640 <bean id="org.hisp.dhis.concept.ConceptService" class="org.hisp.dhis.concept.DefaultConceptService">646 <bean id="org.hisp.dhis.concept.ConceptService" class="org.hisp.dhis.concept.DefaultConceptService">
641 <property name="conceptStore" ref="org.hisp.dhis.concept.ConceptStore" />647 <property name="conceptStore" ref="org.hisp.dhis.concept.ConceptStore" />
642 </bean>648 </bean>
643649
=== 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 @@
1package org.hisp.dhis.webapi.controller;
2
3/*
4 * Copyright (c) 2004-2014, University of Oslo
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 * Redistributions of source code must retain the above copyright notice, this
10 * list of conditions and the following disclaimer.
11 *
12 * Redistributions in binary form must reproduce the above copyright notice,
13 * this list of conditions and the following disclaimer in the documentation
14 * and/or other materials provided with the distribution.
15 * Neither the name of the HISP project nor the names of its contributors may
16 * be used to endorse or promote products derived from this software without
17 * specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
23 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
26 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31import org.apache.commons.logging.Log;
32import org.apache.commons.logging.LogFactory;
33import org.hisp.dhis.email.EmailService;
34import org.hisp.dhis.user.CurrentUserService;
35import org.hisp.dhis.webapi.utils.ContextUtils;
36import org.springframework.beans.factory.annotation.Autowired;
37import org.springframework.stereotype.Controller;
38import org.springframework.web.bind.annotation.RequestMapping;
39import org.springframework.web.bind.annotation.RequestMethod;
40import org.springframework.web.bind.annotation.ResponseBody;
41
42import javax.servlet.http.HttpServletRequest;
43import javax.servlet.http.HttpServletResponse;
44
45/**
46 * @author Halvdan Hoem Grelland <halvdanhg@gmail.com>
47 */
48@Controller
49@RequestMapping( value = EmailController.RESOURCE_PATH )
50public class EmailController
51{
52 private static final Log log = LogFactory.getLog( EmailController.class );
53
54 public static final String RESOURCE_PATH = "/email";
55
56 //--------------------------------------------------------------------------
57 // Dependencies
58 //--------------------------------------------------------------------------
59
60 @Autowired
61 private EmailService emailService;
62
63 @Autowired
64 private CurrentUserService currentUserService;
65
66 @RequestMapping( value = "/sendTestEmail" , method = RequestMethod.POST, produces = ContextUtils.CONTENT_TYPE_TEXT )
67 public @ResponseBody String sendTestEmail( HttpServletRequest request, HttpServletResponse response )
68 {
69 String responseMessage;
70 String userEmail = currentUserService.getCurrentUser().getEmail();
71 boolean smtpConfigured = emailService.emailEnabled();
72 boolean userEmailConfigured = userEmail != null && !userEmail.isEmpty();
73
74 if( smtpConfigured && userEmailConfigured )
75 {
76 response.setStatus( HttpServletResponse.SC_OK );
77 emailService.sendTestEmail( );
78
79 responseMessage = "A test email was sent to " + userEmail;
80 }
81 else if( userEmailConfigured )
82 {
83 response.setStatus( HttpServletResponse.SC_ACCEPTED );
84 responseMessage = "Could not send test email to " + userEmail + ": SMTP is not configured";
85 }
86 else /* smtpConfigured */
87 {
88 response.setStatus( HttpServletResponse.SC_ACCEPTED );
89 responseMessage = "Could not send test email: no user email address configured";
90 }
91
92 return responseMessage;
93 }
94}
095
=== 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 @@
15 });15 });
16 });16 });
17 17
18 jQuery( '#smtpHostName' ).blur();18 jQuery( '#smtpHostName' ).blur();
19
20 jQuery( "#sendTestEmail" ).click( function ( e ){
21 e.preventDefault();
22 jQuery.post( '/api/email/sendTestEmail',
23 function( reply ) {
24 setHeaderDelayMessage ( reply );
25 });
26 });
19 });27 });
28
20</script>29</script>
2130
22<h3>$i18n.getString( "smtp_settings" ) #openHelp( "systemEmailSettings" )</h3>31<h3>$i18n.getString( "smtp_settings" ) #openHelp( "systemEmailSettings" )</h3>
@@ -54,6 +63,11 @@
5463
55<div class="setting"><input type="text" id="emailSender" name="emailSender" value="$!emailSender" autocomplete="off" placeholder="noreply&#64;dhis2.org"></div>64<div class="setting"><input type="text" id="emailSender" name="emailSender" value="$!emailSender" autocomplete="off" placeholder="noreply&#64;dhis2.org"></div>
5665
57<div class="setting"><input type="button" value="$i18n.getString( 'save' )" style="width:10em"></div>66<div class="setting">
67 <input type="button" value="$i18n.getString( 'save' )" style="width:10em">
68 <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>
69</div>
5870
59</form>71</form>
72
73