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.Objects;
021import java.util.Set;
022
023import org.ametys.core.group.Group;
024import org.ametys.core.group.GroupIdentity;
025import org.ametys.core.observation.Event;
026import org.ametys.core.user.User;
027import org.ametys.core.user.UserIdentity;
028import org.ametys.plugins.workspaces.ObservationConstants;
029import org.ametys.plugins.workspaces.members.JCRProjectMember;
030import org.ametys.plugins.workspaces.members.JCRProjectMember.MemberType;
031import org.ametys.plugins.workspaces.members.ProjectMemberManager.ProjectMember;
032import org.ametys.plugins.workspaces.project.objects.Project;
033import org.ametys.runtime.config.Config;
034import org.ametys.runtime.i18n.I18nizableText;
035
036/**
037 * Notifier to send mail to a newly added member of a workspace.
038 */
039public class WelcomeMemberMailNotifierObserver extends AbstractMemberMailNotifierObserver
040{
041    @Override
042    public boolean supports(Event event)
043    {
044        return event.getId().equals(ObservationConstants.EVENT_MEMBER_ADDED)
045                && Config.getInstance().getValue("workspaces.member.added.send.notification", true, false); // Check feature enabled
046    }
047
048    @Override
049    protected List<String> getUserToNotify(Event event, Project project)
050    {
051        // async observer, we need to resolve the member
052        String memberId = (String) event.getArguments().get(ObservationConstants.ARGS_MEMBER_ID);
053        JCRProjectMember newMember = _resolver.resolveById(memberId);
054        
055        // get user to notify
056        List<User> newUsersInProject = new ArrayList<>();
057        if (MemberType.USER == newMember.getType())
058        {
059            User user = _userManager.getUser(newMember.getUser());
060            if (_isUserMemberNewToProject(user.getIdentity(), project))
061            {
062                newUsersInProject.add(user);
063            }
064        }
065        else if (MemberType.GROUP == newMember.getType())
066        {
067            GroupIdentity groupIdentity = newMember.getGroup();
068            Group group = _groupManager.getGroup(groupIdentity);
069            if (group != null && project != null)
070            {
071                newUsersInProject = _projectMemberManager.getGroupUsersFromProject(group, project, (currentProject, identity) -> _isGroupMemberNewToTheProject(currentProject, identity, groupIdentity));
072            }
073        }
074        return getUsersEmail(newUsersInProject);
075    }
076    
077    @Override
078    protected I18nizableText getI18nSubject(Event event, Project project)
079    {
080        return new I18nizableText("plugin." + _pluginName, "PROJECT_MAIL_NOTIFICATION_EVENT_SUBJECT_MEMBER_ADDED", List.of(project.getTitle()));
081    }
082    
083    @Override
084    protected String getMailBodyURI(Event event, Project project)
085    {
086        return "cocoon://_plugins/workspaces/notification-mail-member-event";
087    }
088
089    private boolean _isGroupMemberNewToTheProject(Project project, UserIdentity userIdentity, GroupIdentity newGroupToIgnore)
090    {
091        Set<ProjectMember> projectMembers = _projectMemberManager.getProjectMembers(project, false);
092        boolean isUserOfProject = projectMembers.stream()
093                .filter(member -> MemberType.USER == member.getType())
094                .map(ProjectMember::getUser)
095                .map(User::getIdentity)
096                .filter(userIdentity::equals)
097                .findAny()
098                .isPresent();
099        
100        if (isUserOfProject)
101        {
102            // User from group was already part of the project, as a member of type "user"
103            return false;
104        }
105        
106        return _isUserMemberInAGroupMember(userIdentity, newGroupToIgnore, projectMembers);
107    }
108    
109    private boolean _isUserMemberNewToProject(UserIdentity userIdentity, Project project)
110    {
111        Set<ProjectMember> projectMembers = _projectMemberManager.getProjectMembers(project, false);
112        return _isUserMemberInAGroupMember(userIdentity, null, projectMembers);
113    }
114
115    private boolean _isUserMemberInAGroupMember(UserIdentity userIdentity, GroupIdentity newGroupToIgnore, Set<ProjectMember> projectMembers)
116    {
117        return projectMembers.stream()
118                .filter(member -> MemberType.GROUP == member.getType())
119                .map(ProjectMember::getGroup)
120                .filter(group -> newGroupToIgnore == null || !newGroupToIgnore.equals(group.getIdentity()))
121                .filter(Objects::nonNull)
122                .map(Group::getUsers)
123                .flatMap(Set::stream)
124                .filter(userIdentity::equals)
125                .findAny()
126                .isEmpty(); // User was not found in any group of the project, apart from the ignored group
127    }
128}