001/* 002 * Copyright 2026 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.web.repository.comment; 017 018import java.util.ArrayList; 019import java.util.List; 020import java.util.Objects; 021import java.util.Optional; 022import java.util.Set; 023 024import org.apache.avalon.framework.context.Context; 025import org.apache.avalon.framework.context.ContextException; 026import org.apache.avalon.framework.context.Contextualizable; 027import org.apache.avalon.framework.service.ServiceException; 028import org.apache.avalon.framework.service.ServiceManager; 029import org.apache.avalon.framework.service.Serviceable; 030import org.apache.cocoon.components.ContextHelper; 031import org.apache.cocoon.environment.Request; 032import org.apache.commons.lang3.StringUtils; 033 034import org.ametys.cms.content.ContentHelper; 035import org.ametys.cms.repository.Content; 036import org.ametys.cms.repository.comment.Comment; 037import org.ametys.core.observation.Observer; 038import org.ametys.core.user.User; 039import org.ametys.core.user.UserIdentity; 040import org.ametys.core.user.UserManager; 041import org.ametys.core.user.directory.NotUniqueUserException; 042import org.ametys.core.user.population.PopulationContextHelper; 043import org.ametys.core.util.I18nUtils; 044import org.ametys.core.util.language.UserLanguagesManager; 045import org.ametys.runtime.config.Config; 046import org.ametys.runtime.plugin.component.AbstractLogEnabled; 047import org.ametys.runtime.plugin.component.PluginAware; 048import org.ametys.web.WebHelper; 049import org.ametys.web.repository.site.Site; 050import org.ametys.web.repository.site.SiteManager; 051 052/** 053 * Abstract observer to notify comment authors when a comment is created or updated. 054 */ 055public abstract class AbstractNotifyCommentAuthorObserver extends AbstractLogEnabled implements Observer, Serviceable, PluginAware, Contextualizable 056{ 057 /** The i18n utils of runtime */ 058 protected I18nUtils _i18nUtils; 059 060 /** The content helper */ 061 protected ContentHelper _contentHelper; 062 063 /** The plugin */ 064 protected String _pluginName; 065 066 /** The DAO for comments */ 067 protected CommentsDAO _commentsDAO; 068 069 /** The user manager */ 070 protected UserManager _userManager; 071 072 /** The user languages manager */ 073 protected UserLanguagesManager _userLanguagesManager; 074 /** The population context helper */ 075 protected PopulationContextHelper _populationContextHelper; 076 /** The site manager */ 077 protected SiteManager _siteManager; 078 079 /** The avalon context */ 080 protected Context _context; 081 082 @Override 083 public void service(ServiceManager manager) throws ServiceException 084 { 085 _i18nUtils = (I18nUtils) manager.lookup(I18nUtils.ROLE); 086 _contentHelper = (ContentHelper) manager.lookup(ContentHelper.ROLE); 087 _commentsDAO = (CommentsDAO) manager.lookup(org.ametys.cms.repository.comment.CommentsDAO.ROLE); 088 _userManager = (UserManager) manager.lookup(UserManager.ROLE); 089 _userLanguagesManager = (UserLanguagesManager) manager.lookup(UserLanguagesManager.ROLE); 090 _populationContextHelper = (PopulationContextHelper) manager.lookup(PopulationContextHelper.ROLE); 091 _siteManager = (SiteManager) manager.lookup(SiteManager.ROLE); 092 } 093 094 public void contextualize(Context context) throws ContextException 095 { 096 _context = context; 097 } 098 099 public void setPluginInfo(String pluginName, String featureName, String id) 100 { 101 _pluginName = pluginName; 102 } 103 104 public int getPriority() 105 { 106 return MAX_PRIORITY; 107 } 108 109 /** 110 * Get the language to use for the mail notification of a comment 111 * @param content The content commented 112 * @param comment The comment it self 113 * @return The language to use for the mail notification of a comment 114 */ 115 protected String getMailLanguage(Content content, Comment comment) 116 { 117 return getMailLanguage(content, comment.getAuthor(), comment.getAuthorEmail()); 118 } 119 120 /** 121 * Get the language to use for the mail notification of a comment 122 * @param content The content commented 123 * @param commentAuthor The user identity of the comment's author if it exists (null for unauthenticated comment), used to get the user's language 124 * @param commentAuthorEmail The email of the comment's author, used to find a user with this email on the content's site and get its language if the author user identity is not provided 125 * @return The language to use for the mail notification of a comment 126 */ 127 protected String getMailLanguage(Content content, UserIdentity commentAuthor, String commentAuthorEmail) 128 { 129 // If an author user identity is provided from the comment, use its language 130 User authorUser = resolveCommentAuthor(content, commentAuthor, commentAuthorEmail); 131 return getMailLanguage(content, authorUser); 132 } 133 134 /** 135 * Get the language to use for the mail notification of a comment 136 * @param content The content commented 137 * @param user The user to notify. Can be null, in this case the content's language or the default language will be used 138 * @return The language to use for the mail notification of a comment 139 */ 140 protected String getMailLanguage(Content content, User user) 141 { 142 String userLanguage = null; 143 if (user != null) 144 { 145 userLanguage = user.getLanguage(); 146 } 147 148 // If no language was found, use the content's language then the default language 149 return StringUtils.defaultIfBlank(userLanguage, StringUtils.defaultIfBlank(content.getLanguage(), _userLanguagesManager.getDefaultLanguage())); 150 } 151 152 /** 153 * Try to resolve the user author of the comment as a User from author or email provided in the comment 154 * @param content the commented content 155 * @param comment the comment 156 * @return The user author or null if not found 157 */ 158 protected User resolveCommentAuthor(Content content, Comment comment) 159 { 160 return resolveCommentAuthor(content, comment.getAuthor(), comment.getAuthorEmail()); 161 } 162 163 /** 164 * Try to resolve the user author of the comment as a User from author or email provided in the comment 165 * @param content The content commented 166 * @param commentAuthor The user identity of the comment's author if it exists (null for unauthenticated comment), used to get the user's language 167 * @param commentAuthorEmail The email of the comment's author, used to find a user with this email on the content's site and get its language if the author user identity is not provided 168 * @return The user author or null if not found 169 */ 170 protected User resolveCommentAuthor(Content content, UserIdentity commentAuthor, String commentAuthorEmail) 171 { 172 if (commentAuthor != null) 173 { 174 return _userManager.getUser(commentAuthor); 175 } 176 else 177 { 178 Request request = ContextHelper.getRequest(_context); 179 String siteName = WebHelper.getSiteName(request, content); 180 181 List<String> userPopulationsContexts = new ArrayList<>(); 182 userPopulationsContexts.add("/sites/" + siteName); 183 userPopulationsContexts.add("/sites-fo/" + siteName); 184 185 Set<String> userPopulationsOnSite = _populationContextHelper.getUserPopulationsOnContexts(userPopulationsContexts, false, false); 186 try 187 { 188 return _userManager.getUserByEmail(userPopulationsOnSite, commentAuthorEmail); 189 } 190 catch (NotUniqueUserException e) 191 { 192 getLogger().warn("Cannot find user with email '{}'. Multiple users found with this email", commentAuthorEmail, e); 193 return null; 194 } 195 } 196 } 197 198 /** 199 * Get the email sender for the mail notification of a comment 200 * @param content The content commented 201 * @return The email sender for the mail notification of a comment 202 */ 203 protected String getMailSender(Content content) 204 { 205 Request request = ContextHelper.getRequest(_context); 206 String siteName = WebHelper.getSiteName(request, content); 207 Site site = _siteManager.getSite(siteName); 208 if (site != null) 209 { 210 return site.getValue("site-mail-from"); 211 } 212 213 return Config.getInstance().getValue("smtp.mail.from"); 214 } 215 216 /** 217 * Get the email recipient for the mail notification of a comment 218 * @param comment The comment 219 * @return The email recipient for the mail notification of a comment. Can be null or empty. 220 */ 221 protected String getMailRecipient(Comment comment) 222 { 223 String recipient = comment.getAuthorEmail(); 224 if (StringUtils.isBlank(recipient)) 225 { 226 recipient = Optional.ofNullable(comment.getAuthor()) 227 .map(_userManager::getUser) 228 .filter(Objects::nonNull) 229 .map(User::getEmail) 230 .orElse(null); 231 232 } 233 return recipient; 234 } 235 236}