001/* 002 * Copyright 2018 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.userdirectory; 017 018import java.util.ArrayList; 019import java.util.HashSet; 020import java.util.List; 021import java.util.Map; 022import java.util.Set; 023 024import org.apache.avalon.framework.service.ServiceException; 025import org.apache.avalon.framework.service.ServiceManager; 026import org.apache.commons.lang3.tuple.Pair; 027import org.slf4j.Logger; 028 029import org.ametys.cms.content.ContentHelper; 030import org.ametys.cms.repository.Content; 031import org.ametys.cms.repository.WorkflowAwareContent; 032import org.ametys.cms.workflow.ContentWorkflowHelper; 033import org.ametys.core.util.I18nUtils; 034import org.ametys.runtime.i18n.I18nizableText; 035 036import com.opensymphony.workflow.InvalidActionException; 037import com.opensymphony.workflow.WorkflowException; 038 039/** 040 * Delete orgunit component 041 */ 042public class DeleteOrgUnitComponent extends AbstractDeleteUDContentComponent 043{ 044 /** The avalon role. */ 045 public static final String ROLE = DeleteOrgUnitComponent.class.getName(); 046 047 /** The organisation chart page handler */ 048 protected OrganisationChartPageHandler _oCPageHandler; 049 050 /** The content helper */ 051 protected ContentHelper _contentHelper; 052 053 /** The i18n utils */ 054 protected I18nUtils _i18nUtils; 055 056 /** The content workflow helper */ 057 protected ContentWorkflowHelper _contentWorkflowHelper; 058 059 @Override 060 public void service(ServiceManager smanager) throws ServiceException 061 { 062 super.service(smanager); 063 _oCPageHandler = (OrganisationChartPageHandler) smanager.lookup(OrganisationChartPageHandler.ROLE); 064 _contentHelper = (ContentHelper) smanager.lookup(ContentHelper.ROLE); 065 _i18nUtils = (I18nUtils) smanager.lookup(I18nUtils.ROLE); 066 _contentWorkflowHelper = (ContentWorkflowHelper) smanager.lookup(ContentWorkflowHelper.ROLE); 067 } 068 069 @Override 070 public boolean isContentReferenced(Content content, Logger logger) 071 { 072 List<String> ignoreContentTypes = new ArrayList<>(); 073 ignoreContentTypes.add(OrganisationChartPageHandler.ORGUNIT_CONTENT_TYPE); 074 ignoreContentTypes.add(UserDirectoryPageHandler.ABSTRACT_USER_CONTENT_TYPE); 075 076 return _contentHelper.hasReferencingContents(content, ignoreContentTypes, true); 077 } 078 079 @Override 080 protected boolean _checkBeforeDeletion(Content content, Map<String, String> rights, Map<String, Object> results, Logger logger) 081 { 082 // Check right and lock on content it self 083 boolean allRight = _canDeleteContent(content, rights, results); 084 085 // Check lock on parent contents 086 allRight = _checkParentBeforeDeletion(content, results) && allRight; 087 088 // Check lock on users contents 089 allRight = _checkUsersBeforeDeletion(content, results) && allRight; 090 091 // Check right and lock on children to be deleted or modified 092 allRight = _checkChildrenBeforeDeletion(content, rights, results, logger) && allRight; 093 094 return allRight; 095 } 096 097 /** 098 * True if the parent content is not locked 099 * @param content the content 100 * @param results the results map 101 * @return true if the parent content is not locked 102 */ 103 protected boolean _checkParentBeforeDeletion(Content content, Map<String, Object> results) 104 { 105 boolean allRight = true; 106 107 // Check if parents are not locked 108 Content parentContent = _oCPageHandler.getParentContent(content); 109 if (_isLocked(parentContent)) 110 { 111 @SuppressWarnings("unchecked") 112 List<Content> lockedContents = (List<Content>) results.get("locked-contents"); 113 lockedContents.add(parentContent); 114 115 allRight = false; 116 } 117 118 return allRight; 119 } 120 121 /** 122 * True if the users content is not locked 123 * @param content the content 124 * @param results the results map 125 * @return true if the parent content is not locked 126 */ 127 protected boolean _checkUsersBeforeDeletion(Content content, Map<String, Object> results) 128 { 129 boolean allRight = true; 130 131 // Check if users are not locked 132 for (Content user : _oCPageHandler.getUserContents(content)) 133 { 134 if (_isLocked(user)) 135 { 136 @SuppressWarnings("unchecked") 137 List<Content> lockedContents = (List<Content>) results.get("locked-contents"); 138 lockedContents.add(user); 139 140 allRight = false; 141 } 142 } 143 144 return allRight; 145 } 146 147 /** 148 * Browse children to check if deletion could succeed 149 * @param contentToCheck The current content to check 150 * @param results The result 151 * @param rights the map of rights id with its prefix 152 * @param logger The logger 153 * @return true if the deletion can be processed 154 */ 155 protected boolean _checkChildrenBeforeDeletion(Content contentToCheck, Map<String, String> rights, Map<String, Object> results, Logger logger) 156 { 157 boolean allRight = true; 158 159 List<Content> childOrgUnits = _oCPageHandler.getChildContents(contentToCheck); 160 for (Content childOrgUnit : childOrgUnits) 161 { 162 if (!_canDeleteContent(childOrgUnit, rights, results)) 163 { 164 allRight = false; 165 } 166 else if (isContentReferenced(childOrgUnit, logger)) 167 { 168 @SuppressWarnings("unchecked") 169 List<Content> referencedContents = (List<Content>) results.get("referenced-contents"); 170 referencedContents.add(childOrgUnit); 171 172 allRight = false; 173 } 174 else 175 { 176 // Browse children recursively 177 allRight = _checkChildrenBeforeDeletion(childOrgUnit, rights, results, logger) && allRight; 178 } 179 } 180 181 return allRight; 182 } 183 184 @Override 185 protected boolean _removeRelations(Content content, Logger logger) 186 { 187 boolean success = true; 188 189 // Delete relation to parent and users 190 List<Pair<String, Content>> incomingReferences = _contentHelper.getReferencingContents(content); 191 for (Pair<String, Content> refPair : incomingReferences) 192 { 193 Content refContent = refPair.getValue(); 194 String valuePath = refPair.getKey(); 195 196 try 197 { 198 199 // Ignore child orgunits because they are going to be deleted 200 if (valuePath.equals(OrganisationChartPageHandler.CHILD_ORGUNIT_ATTRIBUTE_NAME)) 201 { 202 I18nizableText commentText = new I18nizableText("plugin.user-directory", "PLUGINS_USER_DIRECTORY_WORKFLOW_ACTION_REMOVE_ORGUNIT_REFERENCE_MSG"); 203 String comment = _i18nUtils.translate(commentText, refContent.getLanguage()); 204 _contentWorkflowHelper.removeStringValueFromMultipleMetadata((WorkflowAwareContent) refContent, valuePath, content.getId(), _removeReferenceActionId, comment); 205 } 206 else if (valuePath.equals(UserDirectoryHelper.ORGUNITS_METADATA)) 207 { 208 I18nizableText commentText = new I18nizableText("plugin.user-directory", "PLUGINS_USER_DIRECTORY_WORKFLOW_ACTION_REMOVE_USER_REFERENCE_MSG"); 209 String comment = _i18nUtils.translate(commentText, refContent.getLanguage()); 210 _contentWorkflowHelper.removeStringValueFromMultipleMetadata((WorkflowAwareContent) refContent, valuePath, content.getId(), _removeReferenceActionId, comment); 211 } 212 } 213 catch (WorkflowException | InvalidActionException e) 214 { 215 logger.error("Unable to remove relation to content \"{}\" ({}) for referencing content \"{}\" ({}) ", content.getTitle(), content.getId(), refContent.getTitle(), refContent.getId(), e); 216 success = false; 217 } 218 } 219 220 return success; 221 } 222 223 224 @Override 225 protected Set<String> _getContentIdsToDelete(Content content, Map<String, String> rights, Map<String, Object> results, Logger logger) 226 { 227 Set<String> toDelete = new HashSet<>(); 228 229 if (_canDeleteContent(content, rights, results)) 230 { 231 toDelete.add(content.getId()); 232 233 for (Content childOrgUnit : _oCPageHandler.getChildContents(content)) 234 { 235 if (!isContentReferenced(childOrgUnit, logger) && _removeUsersRelation(childOrgUnit, logger)) 236 { 237 toDelete.addAll(_getContentIdsToDelete(childOrgUnit, rights, results, logger)); 238 } 239 else 240 { 241 // The child program item can not be deleted, remove the relation to the parent and stop iteration 242 @SuppressWarnings("unchecked") 243 List<Content> referencedContents = (List<Content>) results.get("referenced-contents"); 244 referencedContents.add(childOrgUnit); 245 } 246 } 247 } 248 249 return toDelete; 250 } 251 252 /** 253 * Remove users relation 254 * @param content the orgunit content 255 * @param logger The logger 256 * @return true if relations have been removed 257 */ 258 protected boolean _removeUsersRelation(Content content, Logger logger) 259 { 260 boolean success = true; 261 262 // Delete relation users 263 List<Pair<String, Content>> incomingReferences = _contentHelper.getReferencingContents(content); 264 for (Pair<String, Content> refPair : incomingReferences) 265 { 266 Content refContent = refPair.getValue(); 267 String valuePath = refPair.getKey(); 268 269 try 270 { 271 // Just remove when path is from users 272 if (valuePath.equals(UserDirectoryHelper.ORGUNITS_METADATA)) 273 { 274 I18nizableText commentText = new I18nizableText("plugin.user-directory", "PLUGINS_USER_DIRECTORY_WORKFLOW_ACTION_REMOVE_REFERENCE_MSG"); 275 String comment = _i18nUtils.translate(commentText, refContent.getLanguage()); 276 _contentWorkflowHelper.removeStringValueFromMultipleMetadata((WorkflowAwareContent) refContent, valuePath, content.getId(), _removeReferenceActionId, comment); 277 } 278 } 279 catch (WorkflowException | InvalidActionException e) 280 { 281 logger.error("Unable to remove relations to content \"" + content.getTitle() + " (" + content.getId() + ")", e); 282 success = false; 283 } 284 } 285 286 return success; 287 } 288}