001/* 002 * Copyright 2022 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.usermanagement; 017 018import java.time.ZoneId; 019import java.time.ZonedDateTime; 020import java.util.ArrayList; 021import java.util.Date; 022import java.util.HashMap; 023import java.util.List; 024import java.util.Map; 025import java.util.Set; 026import java.util.stream.Collectors; 027 028import org.apache.avalon.framework.context.Context; 029import org.apache.avalon.framework.context.ContextException; 030import org.apache.avalon.framework.context.Contextualizable; 031import org.apache.avalon.framework.service.ServiceException; 032import org.apache.avalon.framework.service.ServiceManager; 033import org.apache.cocoon.components.ContextHelper; 034import org.apache.cocoon.environment.Request; 035import org.apache.commons.collections4.map.HashedMap; 036 037import org.ametys.core.right.RightManager.RightResult; 038import org.ametys.core.ui.Callable; 039import org.ametys.core.ui.StaticClientSideElement; 040import org.ametys.core.user.User; 041import org.ametys.core.user.UserIdentity; 042import org.ametys.core.user.UserManager; 043import org.ametys.core.user.directory.ModifiableUserDirectory; 044import org.ametys.core.user.directory.UserDirectory; 045import org.ametys.core.user.population.UserPopulation; 046import org.ametys.core.user.population.UserPopulationDAO; 047import org.ametys.runtime.i18n.I18nizableText; 048import org.ametys.web.WebHelper; 049import org.ametys.web.usermanagement.UserManagementException.StatusError; 050import org.ametys.web.usermanagement.UserSignupManager.TempUser; 051import org.ametys.web.usermanagement.UserSignupManager.TempUser.TempUserOrigin; 052 053/** 054 * Client side element for sending invitations 055 * 056 */ 057public class SignupInvitationClientSideElement extends StaticClientSideElement implements Contextualizable 058{ 059 060 private Context _context; 061 private UserPopulationDAO _userPopulationDAO; 062 private UserManager _userManager; 063 private UserSignupManager _signupManager; 064 065 public void contextualize(Context context) throws ContextException 066 { 067 _context = context; 068 } 069 070 @Override 071 public void service(ServiceManager serviceManager) throws ServiceException 072 { 073 super.service(serviceManager); 074 _userPopulationDAO = (UserPopulationDAO) serviceManager.lookup(UserPopulationDAO.ROLE); 075 _userManager = (UserManager) serviceManager.lookup(UserManager.ROLE); 076 _signupManager = (UserSignupManager) serviceManager.lookup(UserSignupManager.ROLE); 077 } 078 079 @Override 080 public List<Script> getScripts(boolean ignoreRights, Map<String, Object> contextParameters) 081 { 082 List<Script> scripts = super.getScripts(ignoreRights, contextParameters); 083 084 if (!scripts.isEmpty()) 085 { 086 Request request = ContextHelper.getRequest(_context); 087 String siteName = WebHelper.getSiteName(request); 088 UserIdentity currentUser = _currentUserProvider.getUser(); 089 090 Set<String> allowedPopulationIds = _signupManager.getAllowedUserPopulationForInvitation(siteName); 091 092 List<UserPopulation> populations = allowedPopulationIds.stream() 093 .map(pId -> _userPopulationDAO.getUserPopulation(pId)) 094 .filter(up -> _containsModifiableUserDirectory(up)) 095 .collect(Collectors.toList()); 096 097 if (populations.isEmpty()) 098 { 099 // User has necessary rights but there is no modifiable population 100 return List.of(); 101 } 102 103 Map<String, Object> parameters = scripts.get(0).getParameters(); 104 boolean canInvitAll = _rightManager.hasRight(currentUser, "Web_Rights_HandleInvitations", "/cms") == RightResult.RIGHT_ALLOW; 105 parameters.put("userPopulationOnly", !canInvitAll); 106 107 User user = _userManager.getUser(currentUser); 108 UserDirectory userDirectory = user.getUserDirectory(); 109 if (userDirectory instanceof ModifiableUserDirectory) 110 { 111 parameters.put("defaultUserDirectory", currentUser.getPopulationId() + "#" + userDirectory.getId()); 112 } 113 } 114 115 return scripts; 116 117 } 118 119 /** 120 * Send an invitation 121 * @param siteName the site name 122 * @param popAndUserDirectory the population and user directory 123 * @param email the email 124 * @param lastname the last name. Can be null or empty 125 * @param firstname the first name. Can be null or empty 126 * @return the result map 127 */ 128 @Callable 129 public Map<String, Object> sendInvitation(String siteName, String popAndUserDirectory, String email, String lastname, String firstname) 130 { 131 String[] split = popAndUserDirectory.split("#"); 132 String populationId = split[0]; 133 String userDirectoryId = split[1]; 134 135 try 136 { 137 _signupManager.inviteToSignup(siteName, null, email, populationId, userDirectoryId, lastname, firstname, true, false, true); 138 return Map.of("success", true, "siteName", siteName, "email", email); 139 } 140 catch (UserManagementException e) 141 { 142 Map<String, Object> result = new HashedMap<>(); 143 result.put("success", false); 144 145 StatusError statusError = e.getStatusError(); 146 if (statusError != null) 147 { 148 result.put("message", new I18nizableText("plugin.web", "PLUGINS_WEB_USERS_SEND_INVITATION_ERROR_" + statusError.name())); 149 } 150 151 return result; 152 } 153 } 154 155 /** 156 * Resend an invitation 157 * @param siteName the site name 158 * @param email the email 159 * @param populationId the population id 160 * @param udId the user directory id 161 * @return the result map 162 */ 163 @Callable 164 public Map<String, Object> resendInvitation(String siteName, String email, String populationId, String udId) 165 { 166 try 167 { 168 _signupManager.resendInvitation(siteName, email, populationId, udId); 169 170 TempUser tempUser = _signupManager.getTempUser(siteName, email, populationId, udId); 171 172 Date rawSubscriptionDate = tempUser.getSubscriptionDate(); 173 ZonedDateTime subscriptionDate = rawSubscriptionDate.toInstant().atZone(ZoneId.systemDefault()); 174 175 return Map.of("success", true, "siteName", siteName, "email", email, "subscriptionDate", subscriptionDate); 176 } 177 catch (UserManagementException e) 178 { 179 Map<String, Object> result = new HashedMap<>(); 180 result.put("success", false); 181 182 StatusError statusError = e.getStatusError(); 183 if (statusError != null) 184 { 185 result.put("message", new I18nizableText("plugin.web", "PLUGINS_WEB_USERS_SEND_INVITATION_ERROR_" + statusError.name())); 186 } 187 188 return result; 189 } 190 } 191 192 /** 193 * Delete invitations 194 * @param siteName the site name 195 * @param emails the emails to delete 196 * @return the result map 197 */ 198 @Callable 199 public Map<String, Object> removeInvitation(String siteName, List<String> emails) 200 { 201 Map<String, Object> result = new HashMap<>(); 202 203 List<String> deletedInvitations = new ArrayList<>(); 204 List<String> noRightInvitations = new ArrayList<>(); 205 List<String> noInvitations = new ArrayList<>(); 206 207 try 208 { 209 Set<String> allowedUserPopulation = _signupManager.getAllowedUserPopulationForInvitation(siteName); 210 for (String email : emails) 211 { 212 TempUser tempUser = _signupManager.getTempUser(siteName, email, null, null); 213 if (tempUser != null && tempUser.getOrigin() == TempUserOrigin.INVITATION) 214 { 215 String population = tempUser.getPopulation(); 216 if (allowedUserPopulation.contains(population)) 217 { 218 _signupManager.removeTempUser(siteName, email, null, tempUser.getPopulation(), tempUser.getUserDirectoryId()); 219 deletedInvitations.add(email); 220 } 221 else 222 { 223 noRightInvitations.add(email); 224 } 225 } 226 else 227 { 228 noInvitations.add(email); 229 } 230 } 231 232 result.put("success", true); 233 result.put("deleted-invitations", deletedInvitations); 234 result.put("noright-invitations", noRightInvitations); 235 result.put("no-invitations", noInvitations); 236 237 return result; 238 } 239 catch (UserManagementException e) 240 { 241 result.put("success", false); 242 243 StatusError statusError = e.getStatusError(); 244 if (statusError != null) 245 { 246 result.put("message", new I18nizableText("plugin.web", "PLUGINS_WEB_USERS_REMOVE_INVITATION_ERROR_" + statusError.name())); 247 } 248 249 return result; 250 } 251 } 252 253 private boolean _containsModifiableUserDirectory(UserPopulation up) 254 { 255 return up.getUserDirectories().stream().anyMatch(ud -> ud instanceof ModifiableUserDirectory); 256 } 257}