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.user.CurrentUserProvider; 028import org.ametys.core.user.User; 029import org.ametys.core.util.I18nUtils; 030import org.ametys.core.util.mail.SendMailHelper; 031import org.ametys.core.util.mail.SendMailHelper.MailBuilder; 032import org.ametys.plugins.core.impl.schedule.AbstractStaticSchedulable; 033import org.ametys.plugins.core.user.UserHelper; 034import org.ametys.runtime.config.Config; 035import org.ametys.runtime.i18n.I18nizableText; 036 037import jakarta.mail.MessagingException; 038 039/** 040 * Abstract schedulable that send an email at the end of the execution 041 * 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 042 * If this user has no email address and there is an error during the execution, an email is sent to the system administrator 043 */ 044public abstract class AbstractSendingMailSchedulable extends AbstractStaticSchedulable implements Initializable 045{ 046 /** The utils for i18n */ 047 protected I18nUtils _i18nUtils; 048 /** Mail sender */ 049 protected String _mailSender; 050 /** Sys admin mail */ 051 protected String _sysadminMail; 052 /** Current user provider */ 053 protected CurrentUserProvider _currentUserProvider; 054 /** User helper */ 055 protected UserHelper _userHelper; 056 057 @Override 058 public void service(ServiceManager manager) throws ServiceException 059 { 060 super.service(manager); 061 _i18nUtils = (I18nUtils) manager.lookup(I18nUtils.ROLE); 062 _currentUserProvider = (CurrentUserProvider) manager.lookup(CurrentUserProvider.ROLE); 063 _userHelper = (UserHelper) manager.lookup(UserHelper.ROLE); 064 } 065 066 public void initialize() throws Exception 067 { 068 _mailSender = Config.getInstance().getValue("smtp.mail.from"); 069 _sysadminMail = Config.getInstance().getValue("smtp.mail.sysadminto"); 070 } 071 072 @Override 073 public void execute(JobExecutionContext context) throws Exception 074 { 075 Optional<String> recipient = _getRecipient(context); 076 077 I18nizableText mailSubject = null; 078 I18nizableText mailBody = null; 079 try 080 { 081 _doExecute(context); 082 083 mailSubject = _getSuccessMailSubject(context); 084 mailBody = _getSuccessMailBody(context); 085 } 086 catch (Exception e) 087 { 088 if (recipient.isEmpty()) 089 { 090 recipient = Optional.ofNullable(_sysadminMail) 091 .filter(StringUtils::isNotEmpty); 092 } 093 094 mailSubject = _getErrorMailSubject(context); 095 mailBody = _getErrorMailBody(context, e); 096 097 throw e; 098 } 099 finally 100 { 101 if (recipient.isPresent()) 102 { 103 _sendMail(mailSubject, mailBody, recipient.get(), context); 104 } 105 } 106 } 107 108 /** 109 * Executes the schedulable. 110 * @param context the context 111 * @throws Exception if an error occurred 112 */ 113 protected abstract void _doExecute(JobExecutionContext context) throws Exception; 114 115 /** 116 * Retrieves the optional recipient of the mail 117 * @param context the context 118 * @return the optional recipient of the mail 119 */ 120 protected Optional<String> _getRecipient(JobExecutionContext context) 121 { 122 return Optional.of(_currentUserProvider) 123 .map(CurrentUserProvider::getUser) 124 .map(_userManager::getUser) 125 .map(User::getEmail) 126 .filter(StringUtils::isNotEmpty); 127 } 128 129 /** 130 * Determines if the mail body is in HTML 131 * @param context the context 132 * @return <code>true</code> if the mail body is in HTML, <code>false</code> otherwise 133 * @throws Exception If an error occurs while retrieving if mail body should be HTML 134 */ 135 protected boolean _isMailBodyInHTML(JobExecutionContext context) throws Exception 136 { 137 return false; 138 } 139 140 /** 141 * Retrieves the subject of the success mail 142 * @param context the context 143 * @return the subject of the success mail 144 * @throws Exception If an error occurs while building the mail subject 145 */ 146 protected abstract I18nizableText _getSuccessMailSubject(JobExecutionContext context) throws Exception; 147 148 /** 149 * Retrieves the body of the success mail 150 * @param context the context 151 * @return the body of the success mail 152 * @throws Exception If an error occurs while building the mail body 153 */ 154 protected abstract I18nizableText _getSuccessMailBody(JobExecutionContext context) throws Exception; 155 156 /** 157 * Retrieves the subject of the error mail 158 * @param context the context 159 * @return the subject of the error mail 160 * @throws Exception If an error occurs while building the mail subject 161 */ 162 protected abstract I18nizableText _getErrorMailSubject(JobExecutionContext context) throws Exception; 163 164 /** 165 * Retrieves the body of the error mail 166 * @param context the context 167 * @param throwable the error 168 * @return the body of the error mail 169 * @throws Exception If an error occurs while building the mail body 170 */ 171 protected abstract I18nizableText _getErrorMailBody(JobExecutionContext context, Throwable throwable) throws Exception; 172 173 /** 174 * Send an email 175 * @param subject the email's subject 176 * @param body the email's body 177 * @param recipient the recipient address 178 * @param context the context 179 */ 180 protected void _sendMail (I18nizableText subject, I18nizableText body, String recipient, JobExecutionContext context) 181 { 182 try 183 { 184 MailBuilder mailBuilder = SendMailHelper.newMail() 185 .withSubject(_i18nUtils.translate(subject)) 186 .withRecipient(recipient) 187 .withSender(_mailSender); 188 189 if (_isMailBodyInHTML(context)) 190 { 191 mailBuilder.withHTMLBody(_i18nUtils.translate(body)); 192 } 193 else 194 { 195 mailBuilder.withTextBody(_i18nUtils.translate(body)); 196 } 197 198 mailBuilder.sendMail(); 199 } 200 catch (MessagingException | IOException e) 201 { 202 if (getLogger().isWarnEnabled()) 203 { 204 getLogger().warn("Unable to send the e-mail '" + subject + "' to '" + recipient + "'", e); 205 } 206 } 207 catch (Exception e) 208 { 209 getLogger().error("An unknown error has occured while sending the mail.", e); 210 } 211 } 212}