001/* 002 * Copyright 2021 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.extraction.execution; 017 018import java.io.IOException; 019import java.util.Collection; 020import java.util.HashMap; 021import java.util.Map; 022import java.util.Set; 023 024import org.apache.avalon.framework.activity.Initializable; 025import org.apache.avalon.framework.component.Component; 026import org.apache.avalon.framework.service.ServiceException; 027import org.apache.avalon.framework.service.ServiceManager; 028import org.apache.avalon.framework.service.Serviceable; 029import org.apache.commons.io.FileUtils; 030import org.apache.commons.lang3.StringUtils; 031import org.apache.excalibur.source.SourceException; 032import org.apache.excalibur.source.SourceResolver; 033import org.apache.excalibur.source.TraversableSource; 034import org.apache.excalibur.source.impl.FileSource; 035 036import org.ametys.core.cache.AbstractCacheManager; 037import org.ametys.core.cache.Cache; 038import org.ametys.core.group.GroupIdentity; 039import org.ametys.core.right.ProfileAssignmentStorage.AnonymousOrAnyConnectedKeys; 040import org.ametys.core.right.ProfileAssignmentStorage.UserOrGroup; 041import org.ametys.core.right.ProfileAssignmentStorageExtensionPoint; 042import org.ametys.core.right.RightManager; 043import org.ametys.core.right.RightManager.RightResult; 044import org.ametys.core.ui.Callable; 045import org.ametys.core.user.CurrentUserProvider; 046import org.ametys.core.user.UserIdentity; 047import org.ametys.plugins.core.user.UserHelper; 048import org.ametys.plugins.extraction.ExtractionConstants; 049import org.ametys.plugins.extraction.ExtractionRightAssignmentContext; 050import org.ametys.runtime.i18n.I18nizableText; 051import org.ametys.runtime.plugin.component.AbstractLogEnabled; 052 053/** 054 * Object representing the extraction definition file content 055 */ 056public class ExtractionDAO extends AbstractLogEnabled implements Serviceable, Component, Initializable 057{ 058 /** The Avalon role */ 059 public static final String ROLE = ExtractionDAO.class.getName(); 060 061 /** Extraction author cache id */ 062 private static final String EXTRACTION_AUTHOR_CACHE = ExtractionDAO.class.getName() + "$extractionAuthor"; 063 064 private CurrentUserProvider _userProvider; 065 private RightManager _rightManager; 066 private SourceResolver _sourceResolver; 067 private ExtractionDefinitionReader _definitionReader; 068 private ProfileAssignmentStorageExtensionPoint _profileAssignmentStorageEP; 069 private CurrentUserProvider _currentUserProvider; 070 private AbstractCacheManager _cacheManager; 071 private UserHelper _userHelper; 072 private TraversableSource _root; 073 074 public void service(ServiceManager manager) throws ServiceException 075 { 076 _userProvider = (CurrentUserProvider) manager.lookup(CurrentUserProvider.ROLE); 077 _rightManager = (RightManager) manager.lookup(RightManager.ROLE); 078 _sourceResolver = (SourceResolver) manager.lookup(SourceResolver.ROLE); 079 _definitionReader = (ExtractionDefinitionReader) manager.lookup(ExtractionDefinitionReader.ROLE); 080 _profileAssignmentStorageEP = (ProfileAssignmentStorageExtensionPoint) manager.lookup(ProfileAssignmentStorageExtensionPoint.ROLE); 081 _currentUserProvider = (CurrentUserProvider) manager.lookup(CurrentUserProvider.ROLE); 082 _cacheManager = (AbstractCacheManager) manager.lookup(AbstractCacheManager.ROLE); 083 _userHelper = (UserHelper) manager.lookup(UserHelper.ROLE); 084 } 085 086 public void initialize() throws Exception 087 { 088 _root = (TraversableSource) _sourceResolver.resolveURI(ExtractionConstants.DEFINITIONS_DIR); 089 090 _cacheManager.createRequestCache(EXTRACTION_AUTHOR_CACHE, 091 new I18nizableText("plugin.extraction", "PLUGINS_EXTRACTION_CACHE_DEFINITION_AUTHOR_LABEL"), 092 new I18nizableText("plugin.extraction", "PLUGINS_EXTRACTION_CACHE_DEFINITION_AUTHOR_DESCRIPTION"), 093 true); 094 } 095 096 /** 097 * Get the root container properties 098 * @return The root container properties 099 * @throws IOException If an error occurred while reading folder 100 */ 101 @Callable 102 public Map<String, Object> getRootProperties() throws IOException 103 { 104 String rootURI = ExtractionConstants.DEFINITIONS_DIR; 105 TraversableSource rootDir = (TraversableSource) _sourceResolver.resolveURI(rootURI); 106 Map<String, Object> infos = getExtractionContainerProperties(rootDir); 107 return infos; 108 } 109 110 /** 111 * Get extraction container properties 112 * @param folder the source of the extraction container 113 * @return The extraction container properties 114 */ 115 public Map<String, Object> getExtractionContainerProperties(TraversableSource folder) 116 { 117 Map<String, Object> infos = new HashMap<>(); 118 119 UserIdentity currentUser = _userProvider.getUser(); 120 121 infos.put("canRead", canRead(currentUser, folder)); 122 infos.put("canRename", canRename(currentUser, folder)); 123 infos.put("canWrite", canWrite(currentUser, folder)); 124 infos.put("canDelete", canDelete(currentUser, folder)); 125 infos.put("canAssignRights", canAssignRights(currentUser, folder)); 126 127 return infos; 128 } 129 130 /** 131 * Get extraction properties 132 * @param extraction the extraction 133 * @param file the source of the extraction 134 * @return The extraction properties 135 */ 136 public Map<String, Object> getExtractionProperties(Extraction extraction, TraversableSource file) 137 { 138 Map<String, Object> infos = new HashMap<>(); 139 140 UserIdentity currentUser = _userProvider.getUser(); 141 infos.put("descriptionId", extraction.getDescriptionId()); 142 143 UserIdentity author = extraction.getAuthor(); 144 infos.put("author", _userHelper.user2json(author)); 145 146 infos.put("canRead", canRead(currentUser, file, author)); 147 infos.put("canWrite", canWrite(currentUser, file, author)); 148 infos.put("canDelete", canDelete(currentUser, file, author)); 149 infos.put("canAssignRights", canAssignRights(currentUser, file, author)); 150 151 return infos; 152 } 153 154 /** 155 * Check if a folder has a descendant in read access for a given user 156 * @param userIdentity the user 157 * @param folder the source of the extraction container 158 * @return <code>true</code> if the folder has a descendant in read access, <code>false</code> otherwise 159 */ 160 public Boolean hasAnyReadableDescendant(UserIdentity userIdentity, TraversableSource folder) 161 { 162 try 163 { 164 if (folder.exists()) 165 { 166 for (TraversableSource child : (Collection<TraversableSource>) folder.getChildren()) 167 { 168 if (child.isCollection()) 169 { 170 if (canRead(userIdentity, child) || hasAnyReadableDescendant(userIdentity, child)) 171 { 172 return true; 173 } 174 } 175 else if (child.getName().endsWith(".xml") && canRead(userIdentity, child, getUserIdentityByExtractionPath((FileSource) child))) 176 { 177 return true; 178 } 179 } 180 } 181 182 return false; 183 } 184 catch (SourceException e) 185 { 186 throw new RuntimeException("Cannot list child elements of " + folder.getURI(), e); 187 } 188 } 189 190 /** 191 * Check if a folder have descendant in write access for a given user 192 * @param userIdentity the user identity 193 * @param folder the source of the extraction container 194 * @return true if the user have write right for at least one child of this container 195 */ 196 public Boolean hasAnyWritableDescendant(UserIdentity userIdentity, TraversableSource folder) 197 { 198 return hasAnyWritableDescendant(userIdentity, folder, false); 199 } 200 201 /** 202 * Check if a folder have descendant in write access for a given user 203 * @param userIdentity the user identity 204 * @param folder the source of the extraction container 205 * @param ignoreExtraction true to ignore extraction file from search (rights will check only on containers) 206 * @return true if the user have write right for at least one child of this container 207 */ 208 public Boolean hasAnyWritableDescendant(UserIdentity userIdentity, TraversableSource folder, boolean ignoreExtraction) 209 { 210 try 211 { 212 if (folder.exists()) 213 { 214 for (TraversableSource child : (Collection<TraversableSource>) folder.getChildren()) 215 { 216 if (child.isCollection()) 217 { 218 if (canWrite(userIdentity, child) || hasAnyWritableDescendant(userIdentity, child)) 219 { 220 return true; 221 } 222 } 223 else if (!ignoreExtraction && child.getName().endsWith(".xml") && canWrite(userIdentity, child, getUserIdentityByExtractionPath((FileSource) child))) 224 { 225 return true; 226 } 227 } 228 } 229 230 return false; 231 } 232 catch (SourceException e) 233 { 234 throw new RuntimeException("Cannot list child elements of " + folder.getURI(), e); 235 } 236 } 237 238 /** 239 * Checks if a folder has descendants in the right assignment access for a given user 240 * @param userIdentity the user 241 * @param folder the source of the extraction container 242 * @return <code>true</code> if the folder has descendant, <code>false</code> otherwise 243 */ 244 public boolean hasAnyAssignableDescendant(UserIdentity userIdentity, TraversableSource folder) 245 { 246 try 247 { 248 if (folder.exists()) 249 { 250 for (TraversableSource child : (Collection<TraversableSource>) folder.getChildren()) 251 { 252 if (child.isCollection()) 253 { 254 if (canAssignRights(userIdentity, child) || hasAnyAssignableDescendant(userIdentity, child)) 255 { 256 return true; 257 } 258 } 259 else if (child.getName().endsWith(".xml")) 260 { 261 if (canAssignRights(userIdentity, child, getUserIdentityByExtractionPath((FileSource) child))) 262 { 263 return true; 264 } 265 } 266 } 267 } 268 269 return false; 270 } 271 catch (SourceException e) 272 { 273 throw new RuntimeException("Cannot list child elements of " + folder.getURI(), e); 274 } 275 } 276 277 /** 278 * Check if a user has read rights on an extraction container 279 * @param userIdentity the user 280 * @param folder the source of the extraction container 281 * @return <code>true</code> if the user has read rights on an extraction container, <code>false</code> otherwise 282 */ 283 public boolean canRead(UserIdentity userIdentity, TraversableSource folder) 284 { 285 return _rightManager.hasReadAccess(userIdentity, _getExtractionRightPath(folder.getURI())) || canWrite(userIdentity, folder); 286 } 287 288 /** 289 * Check if a user has write rights on an extraction container 290 * @param userIdentity the user 291 * @param folder the source of the extraction container 292 * @return <code>true</code> if the user has write rights on an extraction container, <code>false</code> otherwise 293 */ 294 public boolean canWrite(UserIdentity userIdentity, TraversableSource folder) 295 { 296 return canWrite(userIdentity, folder, false); 297 } 298 299 /** 300 * Determines if the user can rename an extraction container 301 * @param userIdentity the user 302 * @param folder the extraction container 303 * @return true if the user can delete the extraction container 304 */ 305 public boolean canRename(UserIdentity userIdentity, TraversableSource folder) 306 { 307 try 308 { 309 return !_isRoot(folder) // is not root 310 && canWrite(userIdentity, folder) // has write access 311 && canWrite(userIdentity, (TraversableSource) folder.getParent()); // has write access on parent 312 } 313 catch (SourceException e) 314 { 315 throw new RuntimeException("Unable to determine user rights on the extraction container " + folder.getURI(), e); 316 } 317 } 318 319 /** 320 * Determines if the user can delete an extraction container 321 * @param userIdentity the user 322 * @param folder the extraction container 323 * @return true if the user can delete the extraction container 324 */ 325 public boolean canDelete(UserIdentity userIdentity, TraversableSource folder) 326 { 327 try 328 { 329 return !_isRoot(folder) // is not root 330 && canWrite(userIdentity, (TraversableSource) folder.getParent()) // has write access on parent 331 && canWrite(userIdentity, folder, true); // has write access on itselft and each descendant 332 } 333 catch (SourceException e) 334 { 335 throw new RuntimeException("Unable to determine user rights on extraction container " + folder.getURI(), e); 336 } 337 } 338 339 /** 340 * Check if a user has write access on an extraction container 341 * @param userIdentity the user user identity 342 * @param folder the extraction container 343 * @param recursively true to check write access on all descendants recursively 344 * @return true if the user has write access on the extraction container 345 */ 346 public boolean canWrite(UserIdentity userIdentity, TraversableSource folder, boolean recursively) 347 { 348 boolean hasRight = _rightManager.hasRight(userIdentity, ExtractionConstants.MODIFY_EXTRACTION_RIGHT_ID, _getExtractionRightPath(folder.getURI())) == RightResult.RIGHT_ALLOW; 349 if (!hasRight) 350 { 351 return false; 352 } 353 354 try 355 { 356 if (recursively) 357 { 358 for (TraversableSource child : (Collection<TraversableSource>) folder.getChildren()) 359 { 360 if (child.isCollection()) 361 { 362 hasRight = hasRight && canWrite(userIdentity, child, true); 363 } 364 else if (child.getName().endsWith(".xml")) 365 { 366 hasRight = hasRight && canWrite(userIdentity, child, getUserIdentityByExtractionPath((FileSource) child)); 367 } 368 369 if (!hasRight) 370 { 371 return false; 372 } 373 } 374 } 375 376 return hasRight; 377 } 378 catch (SourceException e) 379 { 380 throw new RuntimeException("Unable to determine user rights on extraction container " + folder.getURI(), e); 381 } 382 } 383 384 /** 385 * Check if a user can edit rights on an extraction container 386 * @param userIdentity the user 387 * @param folder the source of the extraction container 388 * @return true if the user can edit rights on an extraction container 389 */ 390 public boolean canAssignRights(UserIdentity userIdentity, TraversableSource folder) 391 { 392 try 393 { 394 return _rightManager.hasRight(userIdentity, "Runtime_Rights_Rights_Handle", "/cms") == RightResult.RIGHT_ALLOW 395 || !_isRoot(folder) // is not root 396 && canWrite(userIdentity, (TraversableSource) folder.getParent()) // has write access on parent 397 && canWrite(userIdentity, folder, true); // has write access on itselft and each descendant 398 } 399 catch (SourceException e) 400 { 401 throw new RuntimeException("Unable to determine the user rights on the extraction container " + folder.getURI(), e); 402 } 403 } 404 405 /** 406 * Determines if the extraction container is the root node 407 * @param folder the extraction container 408 * @return true if is root 409 */ 410 protected boolean _isRoot(TraversableSource folder) 411 { 412 return trimLastFileSeparator(_root.getURI()).equals(trimLastFileSeparator(folder.getURI())); 413 } 414 415 /** 416 * Checks if a user has read rights on an extraction 417 * @param userIdentity the user 418 * @param extractionSrc the source for the extraction 419 * @param author the author of extraction 420 * @return <code>true</code> if the user has read rights on an extraction, <code>false</code> otherwise 421 */ 422 public boolean canRead(UserIdentity userIdentity, TraversableSource extractionSrc, UserIdentity author) 423 { 424 return userIdentity.equals(author) || _rightManager.hasReadAccess(userIdentity, _getExtractionRightPath(extractionSrc.getURI())) || canWrite(userIdentity, extractionSrc, author); 425 } 426 427 /** 428 * Check if a user has write rights on an extraction 429 * @param userIdentity the user 430 * @param extractionSrc the source for the extraction 431 * @param author the author of extraction 432 * @return <code>true</code> if the user has write rights on an extraction, <code>false</code> otherwise 433 */ 434 public boolean canWrite(UserIdentity userIdentity, TraversableSource extractionSrc, UserIdentity author) 435 { 436 return userIdentity.equals(author) || _rightManager.hasRight(userIdentity, ExtractionConstants.MODIFY_EXTRACTION_RIGHT_ID, _getExtractionRightPath(extractionSrc.getURI())) == RightResult.RIGHT_ALLOW; 437 } 438 439 /** 440 * Checks if a user has write rights on an extraction 441 * @param userIdentity the user 442 * @param extractionSrc the source for the extraction 443 * @param author the author of extraction 444 * @return <code>true</code> if the user has write rights on an extraction, <code>false</code> otherwise 445 */ 446 public boolean canDelete(UserIdentity userIdentity, TraversableSource extractionSrc, UserIdentity author) 447 { 448 try 449 { 450 return canWrite(userIdentity, extractionSrc, author) && canWrite(userIdentity, (TraversableSource) extractionSrc.getParent()); 451 } 452 catch (SourceException e) 453 { 454 throw new RuntimeException("Unable to determines user rights on extraction " + extractionSrc.getURI(), e); 455 } 456 } 457 458 /** 459 * Check if a user has right affectation rights on an extraction container 460 * @param userIdentity the user 461 * @param extractionSrc the source for the extraction 462 * @param author the extraction author 463 * @return <code>true</code> if the user has right affectation rights on an extraction, <code>false</code> otherwise 464 */ 465 public boolean canAssignRights(UserIdentity userIdentity, TraversableSource extractionSrc, UserIdentity author) 466 { 467 return canWrite(userIdentity, extractionSrc, author) || _rightManager.hasRight(userIdentity, "Runtime_Rights_Rights_Handle", "/cms") == RightResult.RIGHT_ALLOW; 468 } 469 470 /** 471 * Get the relative path of an extraction or an extraction container 472 * @param path The path of the extraction or extraction container 473 * @return the relative path 474 */ 475 private String _getExtractionRightPath(String path) 476 { 477 // Get only the part after the root folder to get the relative path 478 String relPath = StringUtils.substringAfter(trimLastFileSeparator(path), trimLastFileSeparator(_root.getURI())); 479 480 // In some case, relPath can start with a /, we need to trim it to test if it is an empty path corresponding to the root 481 if (relPath.startsWith("/")) 482 { 483 relPath = StringUtils.substringAfter(relPath, "/"); 484 } 485 486 return StringUtils.isEmpty(relPath) ? ExtractionRightAssignmentContext.ROOT_CONTEXT_PREFIX : ExtractionRightAssignmentContext.ROOT_CONTEXT_PREFIX + "/" + relPath; 487 } 488 489 /** 490 * Get the absolute path of an extraction or an extraction from the context 491 * @param context The context 492 * @return the relative path 493 * @throws IOException if I/O error occurred. 494 */ 495 public String getExtractionAbsolutePathFromContext(String context) throws IOException 496 { 497 String relPath = StringUtils.substringAfter(context, ExtractionRightAssignmentContext.ROOT_CONTEXT_PREFIX); 498 499 return ExtractionConstants.DEFINITIONS_DIR + relPath; 500 } 501 502 /** 503 * Copy rights from one context to another one 504 * @param sourceContext the source context 505 * @param targetContext the target context 506 */ 507 public void copyRights(String sourceContext, String targetContext) 508 { 509 // Get the mapping between users and profiles 510 Map<UserIdentity, Map<UserOrGroup, Set<String>>> profilesForUsers = _profileAssignmentStorageEP.getProfilesForUsers(sourceContext, null); 511 // Copy allowed user assignment profiles to new context 512 profilesForUsers.entrySet() 513 .forEach(entry -> _copyAllowedUsers(entry.getKey(), entry.getValue().get(UserOrGroup.ALLOWED), targetContext)); 514 // Copy denied user assignment profiles to new context 515 profilesForUsers.entrySet() 516 .forEach(entry -> _copyDeniedUsers(entry.getKey(), entry.getValue().get(UserOrGroup.DENIED), targetContext)); 517 518 // Get the mapping between groups and profiles 519 Map<GroupIdentity, Map<UserOrGroup, Set<String>>> profilesForGroups = _profileAssignmentStorageEP.getProfilesForGroups(sourceContext, null); 520 // Copy allowed group assignment profiles to new context 521 profilesForGroups.entrySet() 522 .forEach(entry -> _copyAllowedGroups(entry.getKey(), entry.getValue().get(UserOrGroup.ALLOWED), targetContext)); 523 // Copy denied group assignment profiles to new context 524 profilesForGroups.entrySet() 525 .forEach(entry -> _copyDeniedGroups(entry.getKey(), entry.getValue().get(UserOrGroup.DENIED), targetContext)); 526 527 // Get the mapping between anonymous or any connected user and profiles 528 Map<AnonymousOrAnyConnectedKeys, Set<String>> profilesForAnonymousOrAnyConnectedUser = _profileAssignmentStorageEP.getProfilesForAnonymousAndAnyConnectedUser(sourceContext); 529 // Copy allowed anonymous user assignment profiles to new context 530 profilesForAnonymousOrAnyConnectedUser.get(AnonymousOrAnyConnectedKeys.ANONYMOUS_ALLOWED) 531 .forEach(profileId -> _profileAssignmentStorageEP.allowProfileToAnonymous(profileId, targetContext)); 532 // Copy denied anonymous user assignment profiles to new context 533 profilesForAnonymousOrAnyConnectedUser.get(AnonymousOrAnyConnectedKeys.ANONYMOUS_DENIED) 534 .forEach(profileId -> _profileAssignmentStorageEP.denyProfileToAnonymous(profileId, targetContext)); 535 // Copy allowed any connected user assignment profiles to new context 536 profilesForAnonymousOrAnyConnectedUser.get(AnonymousOrAnyConnectedKeys.ANYCONNECTEDUSER_ALLOWED) 537 .forEach(profileId -> _profileAssignmentStorageEP.allowProfileToAnyConnectedUser(profileId, targetContext)); 538 // Copy denied any connected user assignment profiles to new context 539 profilesForAnonymousOrAnyConnectedUser.get(AnonymousOrAnyConnectedKeys.ANYCONNECTEDUSER_DENIED) 540 .forEach(profileId -> _profileAssignmentStorageEP.denyProfileToAnyConnectedUser(profileId, targetContext)); 541 } 542 543 private void _copyAllowedUsers(UserIdentity userIdentity, Set<String> profiles, String context) 544 { 545 profiles.forEach(profile -> _profileAssignmentStorageEP.allowProfileToUser(userIdentity, profile, context)); 546 } 547 548 private void _copyDeniedUsers(UserIdentity userIdentity, Set<String> profiles, String context) 549 { 550 profiles.forEach(profile -> _profileAssignmentStorageEP.denyProfileToUser(userIdentity, profile, context)); 551 } 552 553 private void _copyAllowedGroups(GroupIdentity groupIdentity, Set<String> profiles, String context) 554 { 555 profiles.forEach(profile -> _profileAssignmentStorageEP.allowProfileToGroup(groupIdentity, profile, context)); 556 } 557 558 private void _copyDeniedGroups(GroupIdentity groupIdentity, Set<String> profiles, String context) 559 { 560 profiles.forEach(profile -> _profileAssignmentStorageEP.denyProfileToGroup(groupIdentity, profile, context)); 561 } 562 563 /** 564 * Delete rights from a context 565 * @param context the context 566 */ 567 public void deleteRights(String context) 568 { 569 // Get the mapping between users and profiles 570 Map<UserIdentity, Map<UserOrGroup, Set<String>>> profilesForUsers = _profileAssignmentStorageEP.getProfilesForUsers(context, null); 571 // Copy allowed user assignment profiles to new context 572 profilesForUsers.entrySet() 573 .forEach(entry -> _removeAllowedUsers(entry.getKey(), entry.getValue().get(UserOrGroup.ALLOWED), context)); 574 // Copy denied user assignment profiles to new context 575 profilesForUsers.entrySet() 576 .forEach(entry -> _removeDeniedUsers(entry.getKey(), entry.getValue().get(UserOrGroup.DENIED), context)); 577 578 // Get the mapping between groups and profiles 579 Map<GroupIdentity, Map<UserOrGroup, Set<String>>> profilesForGroups = _profileAssignmentStorageEP.getProfilesForGroups(context, null); 580 // Copy allowed group assignment profiles to new context 581 profilesForGroups.entrySet() 582 .forEach(entry -> _removeAllowedGroups(entry.getKey(), entry.getValue().get(UserOrGroup.ALLOWED), context)); 583 // Copy denied group assignment profiles to new context 584 profilesForGroups.entrySet() 585 .forEach(entry -> _removeDeniedGroups(entry.getKey(), entry.getValue().get(UserOrGroup.DENIED), context)); 586 587 // Get the mapping between anonymous or any connected user and profiles 588 Map<AnonymousOrAnyConnectedKeys, Set<String>> profilesForAnonymousOrAnyConnectedUser = _profileAssignmentStorageEP.getProfilesForAnonymousAndAnyConnectedUser(context); 589 // Copy allowed anonymous user assignment profiles to new context 590 profilesForAnonymousOrAnyConnectedUser.get(AnonymousOrAnyConnectedKeys.ANONYMOUS_ALLOWED) 591 .forEach(profileId -> _profileAssignmentStorageEP.removeAllowedProfileFromAnonymous(profileId, context)); 592 // Copy denied anonymous user assignment profiles to new context 593 profilesForAnonymousOrAnyConnectedUser.get(AnonymousOrAnyConnectedKeys.ANONYMOUS_DENIED) 594 .forEach(profileId -> _profileAssignmentStorageEP.removeDeniedProfileFromAnonymous(profileId, context)); 595 // Copy allowed any connected user assignment profiles to new context 596 profilesForAnonymousOrAnyConnectedUser.get(AnonymousOrAnyConnectedKeys.ANYCONNECTEDUSER_ALLOWED) 597 .forEach(profileId -> _profileAssignmentStorageEP.removeAllowedProfileFromAnyConnectedUser(profileId, context)); 598 // Copy denied any connected user assignment profiles to new context 599 profilesForAnonymousOrAnyConnectedUser.get(AnonymousOrAnyConnectedKeys.ANYCONNECTEDUSER_DENIED) 600 .forEach(profileId -> _profileAssignmentStorageEP.removeDeniedProfileFromAnyConnectedUser(profileId, context)); 601 } 602 603 private void _removeAllowedUsers(UserIdentity userIdentity, Set<String> profiles, String context) 604 { 605 profiles.forEach(profile -> _profileAssignmentStorageEP.removeAllowedProfileFromUser(userIdentity, profile, context)); 606 } 607 608 private void _removeDeniedUsers(UserIdentity userIdentity, Set<String> profiles, String context) 609 { 610 profiles.forEach(profile -> _profileAssignmentStorageEP.removeDeniedProfileFromUser(userIdentity, profile, context)); 611 } 612 613 private void _removeAllowedGroups(GroupIdentity groupIdentity, Set<String> profiles, String context) 614 { 615 profiles.forEach(profile -> _profileAssignmentStorageEP.removeAllowedProfileFromGroup(groupIdentity, profile, context)); 616 } 617 618 private void _removeDeniedGroups(GroupIdentity groupIdentity, Set<String> profiles, String context) 619 { 620 profiles.forEach(profile -> _profileAssignmentStorageEP.removeDeniedProfileFromGroup(groupIdentity, profile, context)); 621 } 622 623 /** 624 * Move an extraction file or folder inside a given directory 625 * 626 * @param srcRelPath The relative URI of file/folder to move 627 * @param targetRelPath The target relative URI of file/folder to move 628 * @return a result map with the name and uri of moved file in case of 629 * success. 630 * @throws IOException If an error occurred manipulating the source 631 */ 632 @Callable (right = ExtractionConstants.MODIFY_EXTRACTION_RIGHT_ID) 633 public Map<String, Object> moveOrRenameExtractionDefinitionFile(String srcRelPath, String targetRelPath) throws IOException 634 { 635 Map<String, Object> result = new HashMap<>(); 636 637 FileSource srcFile = null; 638 FileSource targetFile = null; 639 try 640 { 641 srcFile = (FileSource) _sourceResolver.resolveURI(ExtractionConstants.DEFINITIONS_DIR + srcRelPath); 642 targetFile = (FileSource) _sourceResolver.resolveURI(ExtractionConstants.DEFINITIONS_DIR + targetRelPath); 643 644 String sourceContext = ExtractionRightAssignmentContext.ROOT_CONTEXT_PREFIX + "/" + srcRelPath; 645 String targetContext = ExtractionRightAssignmentContext.ROOT_CONTEXT_PREFIX + "/" + targetRelPath; 646 647 result = _moveOrRenameSource(srcFile, targetFile, sourceContext, targetContext); 648 649 if (result.containsKey("uri")) 650 { 651 String newURI = (String) result.get("uri"); 652 String path = newURI.substring(_root.getURI().length()); 653 result.put("path", path); 654 } 655 } 656 finally 657 { 658 _sourceResolver.release(srcFile); 659 _sourceResolver.release(targetFile); 660 } 661 662 return result; 663 } 664 665 /** 666 * Move a file or folder 667 * 668 * @param sourceFile The file/folder to move 669 * @param targetFile The target file 670 * @param sourceContext the source context 671 * @param targetContext the target context 672 * @return a result map with the name and uri of moved file in case of 673 * success. 674 * @throws IOException If an error occurred manipulating the source 675 */ 676 private Map<String, Object> _moveOrRenameSource(FileSource sourceFile, FileSource targetFile, String sourceContext, String targetContext) throws IOException 677 { 678 Map<String, Object> result = new HashMap<>(); 679 680 // Check if the user try to move files outside the root folder 681 if (!StringUtils.startsWith(sourceFile.getURI(), _root.getURI()) || !StringUtils.startsWith(targetFile.getURI(), _root.getURI())) 682 { 683 result.put("success", false); 684 result.put("error", "no-exists"); 685 686 getLogger().error("User '{}' tried to move parameter file outside of the root extraction directory.", _currentUserProvider.getUser()); 687 688 return result; 689 } 690 691 if (!sourceFile.exists()) 692 { 693 result.put("success", false); 694 result.put("error", "no-exists"); 695 return result; 696 } 697 698 if (targetFile.exists()) 699 { 700 // If both files are equals, there is no need to rename or move it 701 if (sourceFile.getFile().equals(targetFile.getFile())) 702 { 703 result.put("success", true); 704 result.put("name", targetFile.getName()); 705 result.put("uri", targetFile.getURI()); 706 return result; 707 } 708 else 709 { 710 result.put("success", false); 711 result.put("error", "already-exists"); 712 return result; 713 } 714 } 715 716 copyRightsRecursively(sourceContext, targetContext, sourceFile); 717 if (sourceFile.getFile().isFile()) 718 { 719 FileUtils.moveFile(sourceFile.getFile(), targetFile.getFile()); 720 } 721 else 722 { 723 FileUtils.moveDirectory(sourceFile.getFile(), targetFile.getFile()); 724 } 725 deleteRightsRecursively(sourceContext, targetFile); 726 727 result.put("success", true); 728 result.put("name", targetFile.getName()); 729 result.put("uri", targetFile.getURI()); 730 731 return result; 732 } 733 734 /** 735 * Copy rights from one context to another one 736 * @param sourceContext the source context 737 * @param targetContext the target context 738 * @param file the source of the file to copy 739 */ 740 public void copyRightsRecursively(String sourceContext, String targetContext, TraversableSource file) 741 { 742 copyRights(sourceContext, targetContext); 743 if (file.isCollection()) 744 { 745 try 746 { 747 for (TraversableSource child : (Collection<TraversableSource>) file.getChildren()) 748 { 749 copyRightsRecursively(sourceContext + "/" + child.getName(), targetContext + "/" + child.getName(), child); 750 } 751 } 752 catch (SourceException e) 753 { 754 throw new RuntimeException("Cannot list child elements of " + file.getURI(), e); 755 } 756 } 757 } 758 759 /** 760 * Copy rights from one context to another one 761 * @param context the context 762 * @param file the source of the file to copy 763 */ 764 public void deleteRightsRecursively(String context, TraversableSource file) 765 { 766 deleteRights(context); 767 if (file.isCollection()) 768 { 769 try 770 { 771 for (TraversableSource child : (Collection<TraversableSource>) file.getChildren()) 772 { 773 deleteRightsRecursively(context + "/" + child.getName(), child); 774 } 775 } 776 catch (SourceException e) 777 { 778 throw new RuntimeException("Cannot list child elements of " + file.getURI(), e); 779 } 780 } 781 } 782 783 /** 784 * get the author of extraction 785 * @param extractionPath the path of the extraction 786 * @return the author 787 */ 788 public UserIdentity getUserIdentityByExtractionPath(FileSource extractionPath) 789 { 790 return _getExtractionAuthorCache().get(extractionPath, path -> _getUserIdentityByExtractionFile(path)); 791 792 } 793 794 private UserIdentity _getUserIdentityByExtractionFile(FileSource extractionPath) 795 { 796 try 797 { 798 Extraction extraction = _definitionReader.readExtractionDefinitionFile(extractionPath.getFile()); 799 return extraction.getAuthor(); 800 } 801 catch (Exception e) 802 { 803 throw new RuntimeException("Cannot read extraction " + extractionPath, e); 804 } 805 } 806 807 private Cache<FileSource, UserIdentity> _getExtractionAuthorCache() 808 { 809 return this._cacheManager.get(EXTRACTION_AUTHOR_CACHE); 810 } 811 812 /** 813 * Remove the last separator from the uri if it has any 814 * @param uri the uri 815 * @return the uri without any ending separator 816 */ 817 public static String trimLastFileSeparator(String uri) 818 { 819 return StringUtils.endsWith(uri, "/") ? StringUtils.substringBeforeLast(uri, "/") : uri; 820 } 821 822}