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