001/* 002 * Copyright 2022 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.plugins.forms.helper; 017 018import java.io.IOException; 019import java.util.HashMap; 020import java.util.List; 021import java.util.Map; 022import java.util.Objects; 023import java.util.Optional; 024 025import org.apache.avalon.framework.component.Component; 026import org.apache.avalon.framework.service.ServiceException; 027import org.apache.avalon.framework.service.ServiceManager; 028import org.apache.avalon.framework.service.Serviceable; 029import org.apache.commons.lang.StringUtils; 030 031import org.ametys.core.right.RightManager; 032import org.ametys.core.ui.Callable; 033import org.ametys.core.user.User; 034import org.ametys.core.user.UserManager; 035import org.ametys.core.util.I18nUtils; 036import org.ametys.core.util.mail.SendMailHelper; 037import org.ametys.plugins.forms.dao.FormDAO; 038import org.ametys.plugins.forms.repository.Form; 039import org.ametys.plugins.repository.AmetysObjectResolver; 040import org.ametys.runtime.config.Config; 041import org.ametys.runtime.i18n.I18nizableText; 042import org.ametys.runtime.plugin.component.AbstractLogEnabled; 043import org.ametys.web.repository.page.Page; 044import org.ametys.web.repository.page.SitemapElement; 045import org.ametys.web.repository.site.Site; 046import org.ametys.web.repository.site.SiteManager; 047 048import jakarta.mail.MessagingException; 049 050/** 051 * The helper to schedule opening of form 052 */ 053public class FormInvitationsHelper extends AbstractLogEnabled implements Serviceable, Component 054{ 055 /** Avalon ROLE. */ 056 public static final String ROLE = FormInvitationsHelper.class.getName(); 057 058 /** Ametys object resolver. */ 059 protected AmetysObjectResolver _resolver; 060 061 /** The users manager */ 062 protected UserManager _userManager; 063 064 /** The site manager */ 065 protected SiteManager _siteManager; 066 067 /** The i18n utils */ 068 protected I18nUtils _i18nUtils; 069 070 /** The right manager */ 071 protected RightManager _rightManager; 072 073 /** The limited entries helper */ 074 protected LimitedEntriesHelper _limitedEntriesHelper; 075 076 /** The form DAO */ 077 protected FormDAO _formDAO; 078 079 public void service(ServiceManager manager) throws ServiceException 080 { 081 _resolver = (AmetysObjectResolver) manager.lookup(AmetysObjectResolver.ROLE); 082 _userManager = (UserManager) manager.lookup(UserManager.ROLE); 083 _siteManager = (SiteManager) manager.lookup(SiteManager.ROLE); 084 _i18nUtils = (I18nUtils) manager.lookup(I18nUtils.ROLE); 085 _rightManager = (RightManager) manager.lookup(RightManager.ROLE); 086 _limitedEntriesHelper = (LimitedEntriesHelper) manager.lookup(LimitedEntriesHelper.ROLE); 087 _formDAO = (FormDAO) manager.lookup(FormDAO.ROLE); 088 } 089 090 /** 091 * Sends invitations emails. 092 * @param formId The id of the form. 093 * @param message The message content. 094 * @param siteName The site name. 095 * @param language the language 096 * @return An empty map 097 */ 098 @Callable 099 public Map<String, Object> sendInvitations (String formId, String message, String siteName, String language) 100 { 101 Form form = _resolver.resolveById(formId); 102 _formDAO.checkHandleFormRight(form); 103 104 List<Page> pages = _getFormPages(formId, siteName); 105 if (pages.isEmpty()) 106 { 107 throw new IllegalAccessError("Can't send invitations for form id '" + formId + "' because it is not published."); 108 } 109 110 String subject = _getMailSubject(language); 111 String body = _getMailBody(formId, message, siteName, language); 112 113 Site site = _siteManager.getSite(siteName); 114 String defaultFromValue = Config.getInstance().getValue("smtp.mail.from"); 115 String from = site.getValue("site-mail-from", false, defaultFromValue); 116 for (User user : _getUsersToInvite(form)) 117 { 118 try 119 { 120 String finalMessage = StringUtils.replace(body, "{name}", user.getFullName()); 121 122 SendMailHelper.newMail() 123 .withSubject(subject) 124 .withTextBody(finalMessage) 125 .withSender(from) 126 .withRecipient(user.getEmail()) 127 .sendMail(); 128 } 129 catch (MessagingException | IOException e) 130 { 131 getLogger().warn("Unable to send mail to user " + user.getEmail(), e); 132 } 133 } 134 135 return new HashMap<>(); 136 } 137 138 private List<Page> _getFormPages(String formId, String siteName) 139 { 140 List<Page> pages = _formDAO.getFormPage(formId, siteName) 141 .stream() 142 .filter(Page.class::isInstance) 143 .map(Page.class::cast) 144 .toList(); 145 return pages; 146 } 147 148 /** 149 * Get users to invite to the form (user with mail and who are not answered yet to the form) 150 * @param form the form 151 * @return the users to invite 152 */ 153 protected List<User> _getUsersToInvite(Form form) 154 { 155 // Can invite users if the form is on anonymous read access 156 if (_rightManager.hasAnonymousReadAccess(form)) 157 { 158 return List.of(); 159 } 160 161 return _rightManager.getReadAccessAllowedUsers(form).resolveAllowedUsers(true) 162 .stream() 163 .filter(id -> !_limitedEntriesHelper.hasUserAlreadyAnswer(form, id, null)) // User who are not answered yet 164 .map(id -> _userManager.getUser(id)) // Get user object 165 .filter(Objects::nonNull) // User not null 166 .filter(u -> StringUtils.isNotEmpty(u.getEmail())) // User with a mail 167 .toList(); 168 } 169 170 /** 171 * Get users to invite to the form (user with mail and who are not answered yet to the form) 172 * @param formId The id of the form. 173 * @return The number of users to invite 174 */ 175 @Callable 176 public int getNbOfUsersToInvite(String formId) 177 { 178 Form form = _resolver.resolveById(formId); 179 _formDAO.checkHandleFormRight(form); 180 181 return _getUsersToInvite(form).size(); 182 } 183 184 /** 185 * Get the email subject 186 * @param language the language 187 * @return The subject 188 */ 189 protected String _getMailSubject (String language) 190 { 191 return _i18nUtils.translate(new I18nizableText("plugin.forms", "PLUGINS_FORMS_SEND_INVITATIONS_BOX_SUBJECT"), language); 192 } 193 194 /** 195 * Get the email body 196 * @param formId The form id 197 * @param message The message 198 * @param siteName The site name 199 * @param language the language 200 * @return The text body 201 */ 202 protected String _getMailBody (String formId, String message, String siteName, String language) 203 { 204 Site site = _siteManager.getSite(siteName); 205 String formURI = _getFormURI(formId, siteName, language); 206 207 String replacedMessage = StringUtils.replace(message, "{link}", formURI); 208 replacedMessage = StringUtils.replace(replacedMessage, "{site}", site.getTitle()); 209 210 return replacedMessage; 211 } 212 213 /** 214 * Get the form page uri 215 * @param formId The form id 216 * @param siteName The site name 217 * @param language the language 218 * @return The survey absolute uri 219 */ 220 protected String _getFormURI (String formId, String siteName, String language) 221 { 222 List<Page> pages = _getFormPages(formId, siteName); 223 224 Optional<Page> pageOptional = pages.stream() 225 .filter(p -> p.getSitemapName().equals(language)) 226 .findAny(); 227 228 SitemapElement page = pageOptional.isPresent() ? pageOptional.get() : pages.get(0); 229 Site site = _siteManager.getSite(siteName); 230 return site.getUrl() + "/" + page.getSitemap().getName() + "/" + page.getPathInSitemap() + ".html"; 231 } 232}