001/*
002 *  Copyright 2017 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.workspaces.project.notification;
017
018import java.util.ArrayList;
019import java.util.List;
020import java.util.Map;
021import java.util.Objects;
022import java.util.Set;
023
024import javax.mail.MessagingException;
025
026import org.ametys.core.group.Group;
027import org.ametys.core.group.GroupIdentity;
028import org.ametys.core.observation.Event;
029import org.ametys.core.user.User;
030import org.ametys.core.user.UserIdentity;
031import org.ametys.core.util.mail.SendMailHelper;
032import org.ametys.plugins.workspaces.ObservationConstants;
033import org.ametys.plugins.workspaces.members.JCRProjectMember;
034import org.ametys.plugins.workspaces.members.JCRProjectMember.MemberType;
035import org.ametys.plugins.workspaces.project.objects.Project;
036import org.ametys.runtime.config.Config;
037import org.ametys.runtime.i18n.I18nizableText;
038
039/**
040 * Notifier to send mail to a newly added member of a workspace.
041 */
042public class AddMemberMailNotifierObserver extends AbstractMemberMailNotifierObserver
043{
044    @Override
045    public boolean supports(Event event)
046    {
047        return event.getId().equals(ObservationConstants.EVENT_MEMBER_ADDED);
048    }
049
050    @Override
051    public void observe(Event event, Map<String, Object> transientVars) throws Exception
052    {
053        // Check feature enabled
054        boolean notification = Config.getInstance().getValue("workspaces.member.added.send.notification");
055        if (!notification)
056        {
057            return;
058        }
059        
060        Map<String, Object> args = event.getArguments();
061        
062        // Retrieve newly added member
063        String newMemberId = (String) args.get(ObservationConstants.ARGS_MEMBER_ID);
064        JCRProjectMember newMember = _resolver.resolveById(newMemberId);
065
066        // Retrieve project
067        String projectId = (String) args.get(ObservationConstants.ARGS_PROJECT_ID);
068        Project project = _resolver.resolveById(projectId);
069        
070        // Compute subject and body
071        String subject = _i18nUtils.translate(getSubjectI18nizableText(project, newMember));
072        String textBody = _i18nUtils.translate(getBodyI18nizableText(project, newMember));
073        
074        List<User> newUsersInProject = new ArrayList<>();
075        if (MemberType.USER.toString().equals(newMember.getType()))
076        {
077            newUsersInProject.add(_userManager.getUser(newMember.getUser()));
078        }
079        else if (MemberType.GROUP.toString().equals(newMember.getType()))
080        {
081            GroupIdentity groupIdentity = newMember.getGroup();
082            Group group = _groupManager.getGroup(groupIdentity);
083            if (group != null && project != null)
084            {
085                newUsersInProject = _projectMemberManager.getGroupUsersFromProject(group, project, (currentProject, identity) -> _isMemberNewToTheProject(currentProject, identity, groupIdentity));
086            }
087        }
088        
089        // Retrieve mail sender
090        String sender = Config.getInstance().getValue("smtp.mail.from");
091        
092        for (String memberMail : getUsersEmail(newUsersInProject))
093        {
094            try
095            {
096                SendMailHelper.sendMail(subject, null, textBody, memberMail, sender);
097            }
098            catch (MessagingException e)
099            {
100                getLogger().warn("Could not send a notification e-mail to " + memberMail, e);
101            }
102        }
103    }
104    
105    private boolean _isMemberNewToTheProject(Project project, UserIdentity userIdentity, GroupIdentity newGroupToIgnore)
106    {
107        Set<JCRProjectMember> projectMembers = _projectMemberManager.getProjectMembers(project);
108        boolean isUserOfProject = projectMembers.stream()
109                .filter(member -> MemberType.USER.toString().equals(member.getType()))
110                .map(JCRProjectMember::getUser)
111                .filter(userIdentity::equals)
112                .findAny()
113                .isPresent();
114        
115        if (isUserOfProject)
116        {
117            // User from group was already part of the project, as a member of type "user"
118            return false;
119        }
120        
121        return !projectMembers.stream()
122                .filter(member -> MemberType.GROUP.toString().equals(member.getType()))
123                .map(JCRProjectMember::getGroup)
124                .filter(groupIdentity -> !newGroupToIgnore.equals(groupIdentity))
125                .map(_groupManager::getGroup)
126                .filter(Objects::nonNull)
127                .map(Group::getUsers)
128                .flatMap(Set::stream)
129                .filter(userIdentity::equals)
130                .findAny()
131                .isPresent(); // User was found in any group of the project, apart from the ignored group
132    }
133    
134    /**
135     * Gets the {@link I18nizableText} for subject of the mail
136     * @param project the project
137     * @param member the member
138     * @return the subject
139     */
140    protected I18nizableText getSubjectI18nizableText(Project project, JCRProjectMember member)
141    {
142        return new I18nizableText("plugin." + _pluginName, getSubjectI18nKey(), getSubjectParams(project, member));
143    }
144    
145    /**
146     * Gets the i18n subject key
147     * @return the i18n subject key
148     */
149    protected String getSubjectI18nKey()
150    {
151        return "PROJECT_MAIL_NOTIFICATION_SUBJECT_MEMBER_ADDED";
152    }
153    
154    /**
155     * Gets the i18n parameters for subject key
156     * @param project the project
157     * @param member the member
158     * @return the i18n parameters
159     */
160    protected List<String> getSubjectParams(Project project, JCRProjectMember member)
161    {
162        return getI18nParams(project.getTitle()); // {0}
163    }
164    
165    /**
166     * Gets the {@link I18nizableText} for body of the mail
167     * @param project the project
168     * @param member the member
169     * @return the body
170     */
171    protected I18nizableText getBodyI18nizableText(Project project, JCRProjectMember member)
172    {
173        return new I18nizableText("plugin." + _pluginName, getBodyI18nKey(), getBodyParams(project, member));
174    }
175    
176    /**
177     * Gets the i18n body key
178     * @return the i18n body key
179     */
180    protected String getBodyI18nKey()
181    {
182        return "PROJECT_MAIL_NOTIFICATION_BODY_MEMBER_ADDED";
183    }
184    
185    /**
186     * Gets the i18n parameters for body key
187     * @param project the project
188     * @param jcrMember the member
189     * @return the i18n parameters
190     */
191    protected List<String> getBodyParams(Project project, JCRProjectMember jcrMember)
192    {
193        return getI18nParams(
194            project.getTitle(), // {0}
195            getProjectUrl(project)); // {1}
196    }
197
198}