001/* 002 * Copyright 2020 Anyware Services 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.ametys.cms.schedule; 017 018import java.io.IOException; 019import java.util.Optional; 020 021import org.apache.avalon.framework.activity.Initializable; 022import org.apache.avalon.framework.service.ServiceException; 023import org.apache.avalon.framework.service.ServiceManager; 024import org.apache.commons.lang3.StringUtils; 025import org.quartz.JobExecutionContext; 026 027import org.ametys.core.schedule.progression.ContainerProgressionTracker; 028import org.ametys.core.user.CurrentUserProvider; 029import org.ametys.core.user.User; 030import org.ametys.core.user.UserIdentity; 031import org.ametys.core.util.I18nUtils; 032import org.ametys.core.util.mail.SendMailHelper; 033import org.ametys.core.util.mail.SendMailHelper.MailBuilder; 034import org.ametys.plugins.core.impl.schedule.AbstractStaticSchedulable; 035import org.ametys.plugins.core.user.UserHelper; 036import org.ametys.runtime.config.Config; 037import org.ametys.runtime.i18n.I18nizableText; 038 039import jakarta.mail.MessagingException; 040 041/** 042 * Abstract schedulable that send an email at the end of the execution 043 * By default, the email is sent to the user that launched the schedulable. This behavior can be overridden thanks to the {@link #_getRecipient(JobExecutionContext)} method 044 * If this user has no email address and there is an error during the execution, an email is sent to the system administrator 045 */ 046public abstract class AbstractSendingMailSchedulable extends AbstractStaticSchedulable implements Initializable 047{ 048 /** The utils for i18n */ 049 protected I18nUtils _i18nUtils; 050 /** Mail sender */ 051 protected String _mailSender; 052 /** Sys admin mail */ 053 protected String _sysadminMail; 054 /** Current user provider */ 055 protected CurrentUserProvider _currentUserProvider; 056 /** User helper */ 057 protected UserHelper _userHelper; 058 059 @Override 060 public void service(ServiceManager manager) throws ServiceException 061 { 062 super.service(manager); 063 _i18nUtils = (I18nUtils) manager.lookup(I18nUtils.ROLE); 064 _currentUserProvider = (CurrentUserProvider) manager.lookup(CurrentUserProvider.ROLE); 065 _userHelper = (UserHelper) manager.lookup(UserHelper.ROLE); 066 } 067 068 public void initialize() throws Exception 069 { 070 _mailSender = Config.getInstance().getValue("smtp.mail.from"); 071 _sysadminMail = Config.getInstance().getValue("smtp.mail.sysadminto"); 072 } 073 074 @Override 075 public void execute(JobExecutionContext context, ContainerProgressionTracker progressionTracker) throws Exception 076 { 077 Optional<String> recipientMail = _getRecipient(context); 078 079 String defaultLanguage = _userLanguagesManager.getDefaultLanguage(); 080 String language = StringUtils.defaultIfBlank(_getRecipientLanguage(context), defaultLanguage); 081 082 I18nizableText mailSubject = null; 083 String mailBody = null; 084 try 085 { 086 _doExecute(context, progressionTracker); 087 088 mailSubject = _getSuccessMailSubject(context); 089 mailBody = _getSuccessMailBody(context, language); 090 } 091 catch (Exception e) 092 { 093 if (recipientMail.isEmpty()) 094 { 095 recipientMail = Optional.ofNullable(_sysadminMail) 096 .filter(StringUtils::isNotEmpty); 097 // No user language, use the default language 098 language = defaultLanguage; 099 } 100 101 mailSubject = _getErrorMailSubject(context); 102 mailBody = _getErrorMailBody(context, language, e); 103 104 throw e; 105 } 106 finally 107 { 108 if (recipientMail.isPresent() && StringUtils.isNotEmpty(mailBody)) 109 { 110 _sendMail(mailSubject, mailBody, recipientMail.get(), context, language); 111 } 112 } 113 } 114 115 /** 116 * Executes the schedulable. 117 * @param context the context 118 * @param progressionTracker The progression tracker 119 * @throws Exception if an error occurred 120 */ 121 protected abstract void _doExecute(JobExecutionContext context, ContainerProgressionTracker progressionTracker) throws Exception; 122 123 /** 124 * Retrieves the language to use in the mail 125 * @param context the context 126 * @return the language of the recipient or null if none was found 127 */ 128 protected String _getRecipientLanguage(JobExecutionContext context) 129 { 130 UserIdentity userIdentity = _currentUserProvider.getUser(); 131 if (userIdentity != null) 132 { 133 User user = _userManager.getUser(userIdentity); 134 if (user != null) 135 { 136 return user.getLanguage(); 137 } 138 } 139 140 return null; 141 } 142 143 /** 144 * Retrieves the optional recipient of the mail 145 * @param context the context 146 * @return the optional recipient of the mail 147 */ 148 protected Optional<String> _getRecipient(JobExecutionContext context) 149 { 150 return Optional.of(_currentUserProvider) 151 .map(CurrentUserProvider::getUser) 152 .map(_userManager::getUser) 153 .map(User::getEmail) 154 .filter(StringUtils::isNotEmpty); 155 } 156 157 /** 158 * Determines if the mail body is in HTML 159 * @param context the context 160 * @return <code>true</code> if the mail body is in HTML, <code>false</code> otherwise 161 * @throws Exception If an error occurs while retrieving if mail body should be HTML 162 */ 163 protected boolean _isMailBodyInHTML(JobExecutionContext context) throws Exception 164 { 165 return false; 166 } 167 168 /** 169 * Retrieves the subject of the success mail 170 * @param context the context 171 * @return the subject of the success mail 172 * @throws Exception If an error occurs while building the mail subject 173 */ 174 protected abstract I18nizableText _getSuccessMailSubject(JobExecutionContext context) throws Exception; 175 176 /** 177 * Retrieves the body of the success mail 178 * @param context the context 179 * @param language The language to use. Should not be null. 180 * @return the body of the success mail 181 * @throws Exception If an error occurs while building the mail body 182 */ 183 protected abstract String _getSuccessMailBody(JobExecutionContext context, String language) throws Exception; 184 185 /** 186 * Retrieves the subject of the error mail 187 * @param context the context 188 * @return the subject of the error mail 189 * @throws Exception If an error occurs while building the mail subject 190 */ 191 protected abstract I18nizableText _getErrorMailSubject(JobExecutionContext context) throws Exception; 192 193 /** 194 * Retrieves the body of the error mail 195 * @param context the context 196 * @param throwable the error 197 * @param language The language to use. Should not be null. 198 * @return the body of the error mail 199 * @throws Exception If an error occurs while building the mail body 200 */ 201 protected abstract String _getErrorMailBody(JobExecutionContext context, String language, Throwable throwable) throws Exception; 202 203 /** 204 * Send an email 205 * @param subject the email's subject 206 * @param body the email's body (to HTML or text format depending on {@link #_isMailBodyInHTML(JobExecutionContext)} 207 * @param recipient the recipient address 208 * @param context the context 209 * @param language The language to use in the mail. Should not be null. 210 */ 211 protected void _sendMail (I18nizableText subject, String body, String recipient, JobExecutionContext context, String language) 212 { 213 try 214 { 215 MailBuilder mailBuilder = SendMailHelper.newMail() 216 .withSubject(_i18nUtils.translate(subject, language)) 217 .withRecipient(recipient) 218 .withSender(_mailSender); 219 220 if (_isMailBodyInHTML(context)) 221 { 222 mailBuilder.withHTMLBody(body); 223 } 224 else 225 { 226 mailBuilder.withTextBody(body); 227 } 228 229 mailBuilder.sendMail(); 230 } 231 catch (MessagingException | IOException e) 232 { 233 if (getLogger().isWarnEnabled()) 234 { 235 getLogger().warn("Unable to send the e-mail '" + subject + "' to '" + recipient + "'", e); 236 } 237 } 238 catch (Exception e) 239 { 240 getLogger().error("An unknown error has occured while sending the mail.", e); 241 } 242 } 243}