001/*
002 *  Copyright 2023 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.activities.projects;
017
018import java.util.List;
019import java.util.Map;
020import java.util.stream.Collectors;
021import java.util.stream.Stream;
022
023import org.apache.avalon.framework.service.ServiceException;
024import org.apache.avalon.framework.service.ServiceManager;
025import org.apache.commons.lang3.StringUtils;
026import org.apache.commons.lang3.tuple.Pair;
027
028import org.ametys.core.group.Group;
029import org.ametys.core.group.GroupIdentity;
030import org.ametys.core.group.GroupManager;
031import org.ametys.core.user.User;
032import org.ametys.core.user.UserIdentity;
033import org.ametys.plugins.repository.AmetysObject;
034import org.ametys.plugins.repository.activities.Activity;
035import org.ametys.plugins.repository.activities.ActivityType;
036import org.ametys.plugins.workspaces.activities.AbstractWorkspacesActivityNotifier;
037import org.ametys.plugins.workspaces.activities.AbstractWorkspacesActivityType;
038import org.ametys.plugins.workspaces.members.JCRProjectMember.MemberType;
039import org.ametys.plugins.workspaces.members.ProjectMemberManager;
040import org.ametys.plugins.workspaces.members.ProjectMemberManager.ProjectMember;
041import org.ametys.plugins.workspaces.project.notification.preferences.NotificationPreferencesHelper.Frequency;
042import org.ametys.plugins.workspaces.project.objects.Project;
043
044/**
045 * Class representing a activity notifier for member added in workspaces
046 */
047public class MemberAddedActivityNotifier extends AbstractWorkspacesActivityNotifier
048{
049    /** The group manager */
050    protected GroupManager _groupManager;
051    
052    /** The project member manager */
053    protected ProjectMemberManager _projectMemberManager;
054
055    @Override
056    public void service(ServiceManager manager) throws ServiceException
057    {
058        super.service(manager);
059        _groupManager = (GroupManager) manager.lookup(GroupManager.ROLE);
060        _projectMemberManager = (ProjectMemberManager) manager.lookup(ProjectMemberManager.ROLE);
061    }
062    
063    public boolean supports(ActivityType activityType)
064    {
065        return activityType instanceof MemberAddedActivityType;
066    }
067    
068    @Override
069    public Map<String, List<String>> getUsersToNotifyByLanguage(Activity activity)
070    {
071        Stream<User> previousUser = null;
072        Project project = _projectManager.getProject(activity.getValue(AbstractWorkspacesActivityType.PROJECT_NAME));
073
074        // if the new member is a user, we just need to inform all other user
075        // we have already check that it is in fact a new member
076        MemberType memberType = MemberType.valueOf(activity.<String> getValue(MemberAddedActivityType.MEMBER_TYPE).toUpperCase());
077        if (MemberType.USER.equals(memberType))
078        {
079            UserIdentity userIdentity = UserIdentity.stringToUserIdentity(activity.getValue(MemberAddedActivityType.MEMBER));
080            if (userIdentity != null)
081            {
082                User newUser = _userManager.getUser(userIdentity);
083                if (newUser != null)
084                {
085                    previousUser = _projectMemberManager.getProjectMembers(project, true).stream().map(ProjectMember::getUser).filter(u -> !u.equals(newUser));
086                }
087            }
088        }
089        else
090        {
091            GroupIdentity groupIdentity = GroupIdentity.stringToGroupIdentity(activity.getValue(MemberAddedActivityType.MEMBER));
092            if (groupIdentity != null)
093            {
094                Group group = _groupManager.getGroup(groupIdentity);
095                if (group != null)
096                {
097                    previousUser = _projectMemberManager.getProjectMembers(project, false).stream()
098                            // we remove the new group from the project members.
099                            .filter(member -> MemberType.USER.equals(member.getType()) || group.equals(member.getGroup()))
100                            // now we can expand all the group. If a user from
101                            // the new group was already present he shall
102                            // receive a notification as an activity was created
103                            .flatMap(member -> {
104                                if (MemberType.USER.equals(member.getType()))
105                                {
106                                    return Stream.<User> of(member.getUser());
107                                }
108                                else
109                                {
110                                    return member.getGroup().getUsers().stream().map(_userManager::getUser);
111                                }
112                            });
113                }
114            }
115        }
116        if (previousUser != null)
117        {
118            String defaultLanguage = _userLanguagesManager.getDefaultLanguage();
119            return previousUser.filter(user -> _notificationPreferenceHelper.askedToBeNotified(user.getIdentity(), activity.getValue(AbstractWorkspacesActivityType.PROJECT_NAME),
120                    Frequency.EACH))
121                    .map(user -> Pair.of(user.getLanguage(), user.getEmail()))
122                    .filter(p -> StringUtils.isNotEmpty(p.getRight()))
123                    .collect(Collectors.groupingBy(
124                            p -> {
125                                return StringUtils.defaultIfBlank(p.getLeft(), defaultLanguage);
126                            },
127                            Collectors.mapping(
128                                    Pair::getRight,
129                                    Collectors.toList()
130                            )
131                        )
132                    );
133        }
134        else
135        {
136            // Something bad happened…
137            return Map.of();
138        }
139    }
140    
141    
142    @Override
143    public String getMailBodyURI(Activity activity)
144    {
145        return "cocoon://_plugins/workspaces/notification-mail-member";
146    }
147    
148    @Override
149    public AmetysObject getTargetAmetysObject(Activity activity)
150    {
151        // we don't need this method as we override the AbstractWorkspacesActivityNotifier::getUsersEmailToNotify method
152        return null;
153    }
154}