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.thesaurus; 017 018import java.util.ArrayList; 019import java.util.Collection; 020import java.util.HashMap; 021import java.util.List; 022import java.util.Map; 023 024import org.apache.avalon.framework.component.Component; 025import org.apache.avalon.framework.service.ServiceException; 026import org.apache.avalon.framework.service.ServiceManager; 027import org.apache.avalon.framework.service.Serviceable; 028import org.apache.commons.collections.ListUtils; 029import org.apache.commons.lang3.ArrayUtils; 030import org.apache.commons.lang3.StringUtils; 031 032import org.ametys.cms.ObservationConstants; 033import org.ametys.cms.contenttype.ContentAttributeDefinition; 034import org.ametys.cms.contenttype.ContentType; 035import org.ametys.cms.contenttype.ContentTypeDefinition; 036import org.ametys.cms.contenttype.ContentTypeExtensionPoint; 037import org.ametys.cms.contenttype.ContentTypesHelper; 038import org.ametys.cms.contenttype.EditContentTypeException; 039import org.ametys.cms.contenttype.EditContentTypeHelper; 040import org.ametys.cms.contenttype.RemoveContentTypeException; 041import org.ametys.cms.data.type.ModelItemTypeConstants; 042import org.ametys.cms.data.type.ModelItemTypeExtensionPoint; 043import org.ametys.cms.repository.Content; 044import org.ametys.cms.repository.ContentDAO; 045import org.ametys.cms.repository.ContentQueryHelper; 046import org.ametys.cms.repository.ContentTypeExpression; 047import org.ametys.core.observation.Event; 048import org.ametys.core.observation.ObservationManager; 049import org.ametys.core.right.RightManager; 050import org.ametys.core.right.RightManager.RightResult; 051import org.ametys.core.ui.Callable; 052import org.ametys.core.user.CurrentUserProvider; 053import org.ametys.plugins.repository.AmetysObjectIterable; 054import org.ametys.plugins.repository.AmetysObjectResolver; 055import org.ametys.plugins.repository.AmetysRepositoryException; 056import org.ametys.plugins.repository.ModifiableTraversableAmetysObject; 057import org.ametys.plugins.repository.RemovableAmetysObject; 058import org.ametys.plugins.repository.RepositoryConstants; 059import org.ametys.plugins.repository.jcr.NameHelper; 060import org.ametys.plugins.repository.query.expression.AndExpression; 061import org.ametys.plugins.repository.query.expression.Expression; 062import org.ametys.plugins.repository.query.expression.Expression.Operator; 063import org.ametys.plugins.repository.query.expression.MetadataExpression; 064import org.ametys.plugins.repository.query.expression.NotExpression; 065import org.ametys.plugins.repository.query.expression.StringExpression; 066import org.ametys.runtime.i18n.I18nizableText; 067import org.ametys.runtime.model.ModelItem; 068import org.ametys.runtime.model.type.ModelItemType; 069import org.ametys.runtime.plugin.component.AbstractLogEnabled; 070import org.ametys.runtime.plugin.component.PluginAware; 071 072/** 073 * DAO for manipulating thesaurus 074 * 075 */ 076public class ThesaurusDAO extends AbstractLogEnabled implements Serviceable, Component, PluginAware 077{ 078 /** The Avalon role */ 079 public static final String ROLE = ThesaurusDAO.class.getName(); 080 081 /** Metadata for related terms */ 082 public static final String MICROTHESAURUS_CONTENT_TYPE_PREFIX = "content-type.org.ametys.plugins.thesaurus.Content.term."; 083 084 /** Id of all microthesaurus super content type*/ 085 public static final String MICROTHESAURUS_ABSTRACT_CONTENT_TYPE = "org.ametys.plugins.thesaurus.Content.term"; 086 087 /** Metadata for related terms */ 088 public static final String METADATA_RELATED_TERMS = "relatedTerms"; 089 /** Metadata for specific terms */ 090 public static final String METADATA_SPECIFIC_TERMS = "specificTerms"; 091 /** Metadata for generic term */ 092 public static final String METADATA_GENERIC_TERM = "genericTerm"; 093 /** Metadata for synonyms */ 094 public static final String METADATA_SYNONYMS = "synonyms"; 095 /** Metadata for applicationNote */ 096 public static final String METADATA_APPLICATION_NOTE = "applicationNote"; 097 /** Metadata for explanatoryNote */ 098 public static final String METADATA_EXPLANATORY_NOTE = "explanatoryNote"; 099 100 private static final String __PLUGIN_NODE_NAME = "thesaurus"; 101 private static final String __ROOT_THESAURII_NODETYPE = RepositoryConstants.NAMESPACE_PREFIX + ":thesaurii"; 102 103 /** Ametys resolver */ 104 protected AmetysObjectResolver _resolver; 105 /** The right manager */ 106 protected RightManager _rightManager; 107 /** The current user provider */ 108 protected CurrentUserProvider _currentUserProvider; 109 /** The extension point for content types */ 110 protected ContentTypeExtensionPoint _contentTypeEP; 111 /** The content types helper */ 112 protected ContentTypesHelper _contentTypesHelper; 113 /** The extension point for available attribute types */ 114 protected ModelItemTypeExtensionPoint _contentAttributeTypeExtensionPoint; 115 /** The contentDAO */ 116 protected ContentDAO _contentDAO; 117 /** The EditContentTypeHelper */ 118 protected EditContentTypeHelper _editContentTypeHelper; 119 /** Ametys observation manger */ 120 protected ObservationManager _observationManager; 121 122 private String _pluginName; 123 124 @Override 125 public void service(ServiceManager manager) throws ServiceException 126 { 127 _resolver = (AmetysObjectResolver) manager.lookup(AmetysObjectResolver.ROLE); 128 _rightManager = (RightManager) manager.lookup(RightManager.ROLE); 129 _currentUserProvider = (CurrentUserProvider) manager.lookup(CurrentUserProvider.ROLE); 130 _contentTypeEP = (ContentTypeExtensionPoint) manager.lookup(ContentTypeExtensionPoint.ROLE); 131 _contentTypesHelper = (ContentTypesHelper) manager.lookup(ContentTypesHelper.ROLE); 132 _contentAttributeTypeExtensionPoint = (ModelItemTypeExtensionPoint) manager.lookup(ModelItemTypeExtensionPoint.ROLE_CONTENT_ATTRIBUTE); 133 _contentDAO = (ContentDAO) manager.lookup(ContentDAO.ROLE); 134 _editContentTypeHelper = (EditContentTypeHelper) manager.lookup(EditContentTypeHelper.ROLE); 135 _observationManager = (ObservationManager) manager.lookup(ObservationManager.ROLE); 136 } 137 138 public void setPluginInfo(String pluginName, String featureName, String id) 139 { 140 _pluginName = pluginName; 141 } 142 143 /** 144 * Get the list of thesaurus 145 * @return the thesaurus 146 */ 147 public AmetysObjectIterable<Thesaurus> getThesaurii() 148 { 149 ModifiableTraversableAmetysObject rootNode = getRootNode(); 150 return rootNode.getChildren(); 151 } 152 153 /** 154 * Get microthesaurii of a thesaurus 155 * @param thesaurusId The id of thesaurus 156 * @return the contentType ids of microthesaurii 157 */ 158 @Callable 159 public List<String> getMicrothesaurii (String thesaurusId) 160 { 161 Thesaurus thesaurus = _resolver.resolveById(thesaurusId); 162 return thesaurus.getMicrothesaurii(); 163 } 164 165 /** 166 * Get the list of ids of all the microthesaurii 167 * @return the list if microthesaurii ids 168 */ 169 @Callable 170 public List<String> getMicrothesaurii() 171 { 172 List<String> microthesauriiList = new ArrayList<>(); 173 AmetysObjectIterable<Thesaurus> thesaurii = getThesaurii(); 174 for (Thesaurus thesaurus: thesaurii) 175 { 176 List<String> microthesaurii = getMicrothesaurii(thesaurus.getId()); 177 microthesauriiList.addAll(microthesaurii); 178 } 179 180 return microthesauriiList; 181 } 182 183 /** 184 * Get the parent thesaurus 185 * @param microThesaurus The microthesaurus 186 * @return the parent thesaurus 187 */ 188 public Thesaurus getParentThesaurus (ContentType microThesaurus) 189 { 190 AmetysObjectIterable<Thesaurus> thesaurii = getThesaurii(); 191 for (Thesaurus thesaurus : thesaurii) 192 { 193 if (thesaurus.getMicrothesaurii().contains(microThesaurus.getId())) 194 { 195 return thesaurus; 196 } 197 } 198 199 return null; 200 } 201 202 /** 203 * Get the contentTypeDefinition for a microthesaurus 204 * @param cTypeId The id of content type for this microthesaurus 205 * @param label The label of the microthesaurus 206 * @param parentThesaurus The parent thesaurus 207 * @return The ContentTypeDefinition of the reference table content type 208 */ 209 private ContentTypeDefinition _getMicrothesaurusContentTypeDefinition(String cTypeId, String label, Thesaurus parentThesaurus) 210 { 211 ContentTypeDefinition cTypeDef = new ContentTypeDefinition(cTypeId); 212 213 cTypeDef.setPluginName(_pluginName); 214 cTypeDef.setLabel(new I18nizableText(label)); 215 cTypeDef.setDescription(new I18nizableText(label)); 216 cTypeDef.setDefaultTitle(new I18nizableText("plugin." + _pluginName, "PLUGINS_THESAURUS_CONTENT_TYPE_TERM_DEFAULT_TITLE")); 217 cTypeDef.setCategory(new I18nizableText(parentThesaurus.getLabel())); 218 cTypeDef.setIconGlyph("ametysicon-letter-a"); 219 cTypeDef.setSupertypeIds(new String[] {MICROTHESAURUS_ABSTRACT_CONTENT_TYPE}); 220 221 // Set tags 222 cTypeDef.setTagsInherited(true); 223 224 // Additional model items 225 List<ModelItem> modelItems = _getModelItems(cTypeId); 226 cTypeDef.setModelItems(modelItems); 227 cTypeDef.setParentRef(METADATA_GENERIC_TERM); 228 229 // Do not override metadatasets from the supertypTerm 230 cTypeDef.setViews(ListUtils.EMPTY_LIST); 231 232 return cTypeDef; 233 } 234 235 /** 236 * Get the additional metadata for a microthesaurus 237 * @param microthesaurusCTypeId The id of content type for this microthesaurus 238 * @return The list of additional metadata definition 239 */ 240 private List<ModelItem> _getModelItems(String microthesaurusCTypeId) 241 { 242 List<ModelItem> modelItems = new ArrayList<>(); 243 ModelItemType contentAttributeType = _contentAttributeTypeExtensionPoint.getExtension(ModelItemTypeConstants.CONTENT_ELEMENT_TYPE_ID); 244 245 // Generic term 246 ContentAttributeDefinition genericTerm = new ContentAttributeDefinition(_contentTypeEP, _contentTypesHelper); 247 genericTerm.setContentTypeId(microthesaurusCTypeId); 248 genericTerm.setName(METADATA_GENERIC_TERM); 249 genericTerm.setMultiple(false); 250 genericTerm.setType(contentAttributeType); 251 genericTerm.setInvertRelationPath(METADATA_SPECIFIC_TERMS); 252 genericTerm.setLabel(new I18nizableText("plugin." + _pluginName, "PLUGINS_THESAURUS_CONTENT_TYPE_TERM_GENERIC_TERMS")); 253 genericTerm.setDescription(new I18nizableText("plugin." + _pluginName, "PLUGINS_THESAURUS_CONTENT_TYPE_TERM_GENERIC_TERMS_DESC")); 254 modelItems.add(genericTerm); 255 256 // Specific terms 257 ContentAttributeDefinition specificTerms = new ContentAttributeDefinition(_contentTypeEP, _contentTypesHelper); 258 specificTerms.setContentTypeId(microthesaurusCTypeId); 259 specificTerms.setName(METADATA_SPECIFIC_TERMS); 260 specificTerms.setMultiple(true); 261 specificTerms.setType(contentAttributeType); 262 specificTerms.setInvertRelationPath(METADATA_GENERIC_TERM); 263 specificTerms.setLabel(new I18nizableText("plugin." + _pluginName, "PLUGINS_THESAURUS_CONTENT_TYPE_TERM_SPECIFIC_TERMS")); 264 specificTerms.setDescription(new I18nizableText("plugin." + _pluginName, "PLUGINS_THESAURUS_CONTENT_TYPE_TERM_SPECIFIC_TERMS_DESC")); 265 modelItems.add(specificTerms); 266 267 // Related terms 268 ContentAttributeDefinition relatedTerms = new ContentAttributeDefinition(_contentTypeEP, _contentTypesHelper); 269 relatedTerms.setContentTypeId(microthesaurusCTypeId); 270 relatedTerms.setName(METADATA_RELATED_TERMS); 271 relatedTerms.setMultiple(true); 272 relatedTerms.setType(contentAttributeType); 273 relatedTerms.setInvertRelationPath(METADATA_RELATED_TERMS); 274 relatedTerms.setLabel(new I18nizableText("plugin." + _pluginName, "PLUGINS_THESAURUS_CONTENT_TYPE_TERM_RELATED_TERMS")); 275 relatedTerms.setDescription(new I18nizableText("plugin." + _pluginName, "PLUGINS_THESAURUS_CONTENT_TYPE_TERM_RELATED_TERMS_DESC")); 276 modelItems.add(relatedTerms); 277 278 return modelItems; 279 } 280 281 /** 282 * Get a thesaurus by its label 283 * @param label the label 284 * @return the thesaurus or null if not found 285 */ 286 public Thesaurus findThesaurusByLabel(String label) 287 { 288 String xpathQuery = "//element(*, " + ThesaurusFactory.THESAURUS_NODETYPE + ")[@ametys-internal:label='" + label + "']"; 289 290 AmetysObjectIterable<Thesaurus> thesaurii = _resolver.query(xpathQuery); 291 return thesaurii.getSize() > 0 ? thesaurii.iterator().next() : null; 292 } 293 294 /** 295 * Creates a thesaurus 296 * @param label The label 297 * @return The id and label of the created microthesaurus 298 */ 299 @Callable 300 public Map<String, Object> createThesaurus (String label) 301 { 302 if (_rightManager.hasRight(_currentUserProvider.getUser(), "Thesaurus_Rights_CreateThesaurus", "/cms") != RightResult.RIGHT_ALLOW) 303 { 304 String errorMessage = "User " + _currentUserProvider.getUser() + " try to create thesaurus with no sufficient rights"; 305 getLogger().error(errorMessage); 306 throw new IllegalStateException(errorMessage); 307 } 308 309 Map<String, Object> result = new HashMap<>(); 310 311 if (findThesaurusByLabel(label) != null) 312 { 313 result.put("success", false); 314 result.put("alreadyExist", true); 315 result.put("label", label); 316 return result; 317 } 318 319 ModifiableTraversableAmetysObject rootNode = getRootNode(); 320 String originalName = NameHelper.filterName(label); 321 322 // Find unique name 323 int index = 2; 324 String name = originalName; 325 while (rootNode.hasChild(name)) 326 { 327 name = originalName + "_" + (index++); 328 } 329 330 Thesaurus thesaurus = rootNode.createChild(name, ThesaurusFactory.THESAURUS_NODETYPE); 331 thesaurus.setLabel(label); 332 333 rootNode.saveChanges(); 334 335 result.put("success", true); 336 result.put("id", thesaurus.getId()); 337 result.put("label", thesaurus.getLabel()); 338 339 return result; 340 } 341 342 /** 343 * Updates a thesaurus 344 * @param thesaurusId The id of microthesaurus 345 * @param label The new label 346 * @return The id and label of the updated microthesaurus 347 * @throws EditContentTypeException if failed to update the existing content types for child microthesaurii. 348 */ 349 @Callable 350 public Map<String, Object> updateThesaurus (String thesaurusId, String label) throws EditContentTypeException 351 { 352 if (_rightManager.hasRight(_currentUserProvider.getUser(), "Thesaurus_Rights_EditThesaurus", "/cms") != RightResult.RIGHT_ALLOW) 353 { 354 String errorMessage = "User " + _currentUserProvider.getUser() + " try to edit thesaurus of id " + thesaurusId + " with no sufficient rights"; 355 getLogger().error(errorMessage); 356 throw new IllegalStateException(errorMessage); 357 } 358 359 Map<String, Object> result = new HashMap<>(); 360 Thesaurus thesaurus = _resolver.resolveById(thesaurusId); 361 362 Thesaurus homonym = findThesaurusByLabel(label); 363 if (homonym != null && !homonym.equals(thesaurus)) 364 { 365 result.put("success", false); 366 result.put("alreadyExist", true); 367 result.put("label", label); 368 return result; 369 } 370 371 // Update category of existing microthesaurii content type 372 Collection<String> microthesaurii = thesaurus.getMicrothesaurii(); 373 if (microthesaurii.size() > 0) 374 { 375 result.put("hasMicrothesaurii", true); 376 for (String microthesaurus: microthesaurii) 377 { 378 ContentType contentType = _contentTypeEP.getExtension(microthesaurus); 379 380 ContentTypeDefinition contentTypeDef = _getMicrothesaurusContentTypeDefinition(contentType.getId(), contentType.getLabel().getLabel(), thesaurus); 381 contentTypeDef.setCategory(new I18nizableText(label)); 382 _editContentTypeHelper.editContentType(contentTypeDef); 383 } 384 } 385 386 thesaurus.setLabel(label); 387 thesaurus.saveChanges(); 388 389 result.put("success", true); 390 result.put("id", thesaurus.getId()); 391 result.put("label", thesaurus.getLabel()); 392 393 return result; 394 } 395 396 /** 397 * Deletes a thesaurus 398 * @param thesaurusId The id of thesaurus 399 * @return The id of the deleted thesaurus 400 */ 401 @Callable 402 public Map<String, Object> deleteThesaurus (String thesaurusId) 403 { 404 if (_rightManager.hasRight(_currentUserProvider.getUser(), "Thesaurus_Rights_EditThesaurus", "/cms") != RightResult.RIGHT_ALLOW) 405 { 406 String errorMessage = "User " + _currentUserProvider.getUser() + " try to delete thesaurus of id " + thesaurusId + " with no sufficient rights"; 407 getLogger().error(errorMessage); 408 throw new IllegalStateException(errorMessage); 409 } 410 411 Map<String, Object> result = new HashMap<>(); 412 413 Thesaurus thesaurus = _resolver.resolveById(thesaurusId); 414 List<String> microthesaurii = thesaurus.getMicrothesaurii(); 415 416 for (String microthesaurusId : microthesaurii) 417 { 418 Map<String, Object> checkResult = checkBeforeMicrothesaurusDeletion(microthesaurusId); 419 boolean checkMicrothesaurusOk = (boolean) checkResult.get("success"); 420 if (!checkMicrothesaurusOk) 421 { 422 result.putAll(checkResult); 423 424 ContentType cType = _contentTypeEP.getExtension(microthesaurusId); 425 426 Map<String, Object> microthesaurusParams = new HashMap<>(); 427 microthesaurusParams.put("id", microthesaurusId); 428 microthesaurusParams.put("label", cType.getLabel()); 429 430 result.put("undeletable-microthesaurus", microthesaurusParams); 431 return result; 432 } 433 } 434 435 436 result.put("id", thesaurus.getId()); 437 result.put("deleted-microthesaurii", new ArrayList<>()); 438 439 // Delete microthesaurus first 440 for (String microthesaurusId : microthesaurii) 441 { 442 ContentType cType = _contentTypeEP.getExtension(microthesaurusId); 443 444 Map<String, Object> microthesaurusParams = new HashMap<>(); 445 microthesaurusParams.put("id", microthesaurusId); 446 microthesaurusParams.put("label", cType.getLabel()); 447 448 Map<String, Object> deletionResult = deleteMicrothesaurus(microthesaurusId); 449 boolean deletionOk = (boolean) deletionResult.get("success"); 450 451 if (!deletionOk) 452 { 453 result.put("success", false); 454 result.put("undeleted-microthesaurus", microthesaurusParams); 455 return result; 456 } 457 else 458 { 459 @SuppressWarnings("unchecked") 460 List<Map<String, Object>> deletedMT = (List<Map<String, Object>>) result.get("deleted-microthesaurii"); 461 deletedMT.add(microthesaurusParams); 462 } 463 } 464 465 // Delete thesaurus 466 thesaurus.remove(); 467 thesaurus.saveChanges(); 468 469 result.put("success", true); 470 return result; 471 } 472 473 /** 474 * Get the label of thesaurus 475 * @param thesaurusId The id of thesaurus 476 * @return The id and label of the thesaurus 477 */ 478 @Callable 479 public String getThesaurusLabel (String thesaurusId) 480 { 481 Thesaurus thesaurus = _resolver.resolveById(thesaurusId); 482 return thesaurus.getLabel(); 483 } 484 485 /** 486 * Get the all terms of a microthesaurus 487 * @param microthesaurusId the id of microthesaurus 488 * @return all terms 489 */ 490 public AmetysObjectIterable<Content> getAllTerms(String microthesaurusId) 491 { 492 Expression cTypeExpr = new ContentTypeExpression(Operator.EQ, microthesaurusId); 493 String xPathQuery = ContentQueryHelper.getContentXPathQuery(cTypeExpr); 494 495 AmetysObjectIterable<Content> terms = _resolver.query(xPathQuery); 496 return terms; 497 } 498 499 /** 500 * Get the root terms of a microthesaurus 501 * @param microthesaurusId the id of microthesaurus 502 * @return root terms 503 */ 504 public AmetysObjectIterable<Content> getRootTerms(String microthesaurusId) 505 { 506 Expression cTypeExpr = new ContentTypeExpression(Operator.EQ, microthesaurusId); 507 Expression genericExpr = new NotExpression(new MetadataExpression(METADATA_GENERIC_TERM)); 508 String xPathQuery = ContentQueryHelper.getContentXPathQuery(new AndExpression(cTypeExpr, genericExpr)); 509 510 AmetysObjectIterable<Content> terms = _resolver.query(xPathQuery); 511 return terms; 512 } 513 514 /** 515 * Get direct child terms of a term 516 * @param microthesaurusId the id of microthesaurus 517 * @param parentId The parent Id 518 * @return The child terms 519 */ 520 public AmetysObjectIterable<Content> getChildTerms(String microthesaurusId, String parentId) 521 { 522 Expression cTypeExpr = new ContentTypeExpression(Operator.EQ, microthesaurusId); 523 Expression genericExpr = new StringExpression(METADATA_GENERIC_TERM, Operator.EQ, parentId); 524 String xPathQuery = ContentQueryHelper.getContentXPathQuery(new AndExpression(cTypeExpr, genericExpr)); 525 526 AmetysObjectIterable<Content> terms = _resolver.query(xPathQuery); 527 return terms; 528 } 529 530 /** 531 * Determines if a term which belongs to a microthesaurus is referenced by contents outside the microthesaurus 532 * @param microthesaurusId the id of microthesaurus 533 * @param term the content term 534 * @return true if the term has at least one referencing content outside the microthesaurus 535 */ 536 public boolean hasReferencingContents(String microthesaurusId, Content term) 537 { 538 Collection<Content> referencingContents = term.getReferencingContents(); 539 540 for (Content referencingContent : referencingContents) 541 { 542 if (!ArrayUtils.contains(referencingContent.getTypes(), microthesaurusId)) 543 { 544 return true; 545 } 546 } 547 548 return false; 549 } 550 551 /** 552 * Creates a microthesaurus 553 * @param label The label 554 * @param thesaurusId The id of parent thesaurus 555 * @param microthesaurusName the name of the microthesaurus 556 * @return The id and label of the created microthesaurus 557 * @throws EditContentTypeException if failed to create the microthesaurus content type 558 */ 559 @Callable 560 public Map<String, Object> createMicrothesaurus (String label, String thesaurusId, String microthesaurusName) throws EditContentTypeException 561 { 562 Thesaurus thesaurus = _resolver.resolveById(thesaurusId); 563 564 Map<String, Object> result = new HashMap<>(); 565 566 String cTypeId = MICROTHESAURUS_CONTENT_TYPE_PREFIX + microthesaurusName; 567 568 List<String> microthesaurii = getMicrothesaurii(); 569 570 // Check if microthesaurus does not already exist 571 if (microthesaurii.contains(cTypeId)) 572 { 573 result.put("success", false); 574 result.put("alreadyExist", microthesaurusName); 575 576 int index = 2; 577 while (microthesaurii.contains(cTypeId)) 578 { 579 cTypeId = MICROTHESAURUS_CONTENT_TYPE_PREFIX + microthesaurusName + "-" + index; 580 index++; 581 } 582 583 result.put("suggestedName", StringUtils.substringAfter(cTypeId, MICROTHESAURUS_CONTENT_TYPE_PREFIX)); 584 return result; 585 } 586 587 // Create content type 588 ContentTypeDefinition contentType = _getMicrothesaurusContentTypeDefinition(cTypeId, label, thesaurus); 589 _editContentTypeHelper.createContentType(contentType); 590 591 thesaurus.addMicrothesaurus(cTypeId); 592 thesaurus.saveChanges(); 593 594 result.put("success", true); 595 result.put("id", microthesaurusName); 596 result.put("label", label); 597 result.put("thesaurusId", thesaurusId); 598 599 return result; 600 } 601 602 /** 603 * Edit a microthesaurus 604 * @param microthesaurusId The id of microthesaurus to edit 605 * @param label The new label 606 * @return The id and label of the updated microthesaurus 607 * @throws EditContentTypeException if failed to update the content type for this microthesaurus 608 */ 609 @Callable 610 public Map<String, Object> updateMicrothesaurus (String microthesaurusId, String label) throws EditContentTypeException 611 { 612 if (_rightManager.hasRight(_currentUserProvider.getUser(), "Thesaurus_Rights_EditMicrothesaurus", "/cms") != RightResult.RIGHT_ALLOW) 613 { 614 String errorMessage = "User " + _currentUserProvider.getUser() + " try to edit microthesaurus of id '" + microthesaurusId + "' with no sufficient rights"; 615 getLogger().error(errorMessage); 616 throw new IllegalStateException(errorMessage); 617 } 618 619 ContentType microThesaurus = _contentTypeEP.getExtension(microthesaurusId); 620 621 Thesaurus thesaurus = getParentThesaurus(microThesaurus); 622 623 // Update content type 624 ContentTypeDefinition contentTypeDef = _getMicrothesaurusContentTypeDefinition(microThesaurus.getId(), label, thesaurus); 625 _editContentTypeHelper.editContentType(contentTypeDef); 626 627 Map<String, Object> result = new HashMap<>(); 628 result.put("id", microThesaurus.getId()); 629 result.put("label", microThesaurus.getLabel()); 630 result.put("thesaurusId", thesaurus.getId()); 631 result.put("success", true); 632 633 return result; 634 } 635 636 /** 637 * Do some check before microthesaurus deletion 638 * @param microthesaurusId the id of microthesaurus 639 * @return the check result 640 */ 641 @Callable 642 public Map<String, Object> checkBeforeMicrothesaurusDeletion(String microthesaurusId) 643 { 644 Map<String, Object> result = new HashMap<>(); 645 646 AmetysObjectIterable<Content> terms = getAllTerms(microthesaurusId); 647 if (terms.getSize() == 0) 648 { 649 result.put("success", true); 650 result.put("emptyMicrothesaurus", true); 651 return result; 652 } 653 654 for (Content term : terms) 655 { 656 if (hasReferencingContents(microthesaurusId, term)) 657 { 658 result.put("success", false); 659 result.put("hasReferencingContents", true); 660 return result; 661 } 662 } 663 664 result.put("success", true); 665 return result; 666 } 667 668 /** 669 * Deletes a microthesaurus 670 * @param microthesaurusId The id of microthesaurus 671 * @return The id of the deleted microthesaurus 672 */ 673 @Callable 674 public Map<String, Object> deleteMicrothesaurus(String microthesaurusId) 675 { 676 if (_rightManager.hasRight(_currentUserProvider.getUser(), "Thesaurus_Rights_EditMicrothesaurus", "/cms") != RightResult.RIGHT_ALLOW) 677 { 678 String errorMessage = "User " + _currentUserProvider.getUser() + " try to delete microthesaurus of id '" + microthesaurusId + "' with no sufficient rights"; 679 getLogger().error(errorMessage); 680 throw new IllegalStateException(errorMessage); 681 } 682 683 Map<String, Object> result = checkBeforeMicrothesaurusDeletion(microthesaurusId); 684 685 boolean checkOk = (boolean) result.get("success"); 686 if (!checkOk) 687 { 688 return result; 689 } 690 691 // Remove existing terms 692 AmetysObjectIterable<Content> terms = getAllTerms(microthesaurusId); 693 for (Content term : terms) 694 { 695 _deleteTerm(term); 696 } 697 698 ContentType cType = _contentTypeEP.getExtension(microthesaurusId); 699 Thesaurus thesaurus = getParentThesaurus(cType); 700 701 result.put("thesaurusId", thesaurus.getId()); 702 result.put("id", microthesaurusId); 703 result.put("label", cType.getLabel()); 704 705 try 706 { 707 _editContentTypeHelper.removeContentType(microthesaurusId); 708 } 709 catch (RemoveContentTypeException e) 710 { 711 getLogger().error("The microthesaurus with id {} can not be removed", microthesaurusId, e); 712 result.put("success", false); 713 714 return result; 715 } 716 717 // Remove thesaurus from parent thesaurus 718 thesaurus.removeMicrothesaurus(microthesaurusId); 719 thesaurus.saveChanges(); 720 721 result.put("success", true); 722 723 return result; 724 } 725 726 private void _deleteTerm (Content term) 727 { 728 Map<String, Object> eventParams = new HashMap<>(); 729 eventParams.put(ObservationConstants.ARGS_CONTENT, term); 730 eventParams.put(ObservationConstants.ARGS_CONTENT_NAME, term.getName()); 731 eventParams.put(ObservationConstants.ARGS_CONTENT_ID, term.getId()); 732 733 _observationManager.notify(new Event(ObservationConstants.EVENT_CONTENT_DELETING, _currentUserProvider.getUser(), eventParams)); 734 735 RemovableAmetysObject removableContent = (RemovableAmetysObject) term; 736 737 // Remove the content. 738 removableContent.remove(); 739 740 _observationManager.notify(new Event(ObservationConstants.EVENT_CONTENT_DELETED, _currentUserProvider.getUser(), eventParams)); 741 } 742 /** 743 * Get the root plugin storage object. 744 * @return the root plugin storage object. 745 * @throws AmetysRepositoryException if a repository error occurs. 746 */ 747 public ModifiableTraversableAmetysObject getRootNode() throws AmetysRepositoryException 748 { 749 try 750 { 751 ModifiableTraversableAmetysObject pluginsNode = _resolver.resolveByPath("/ametys:plugins"); 752 753 ModifiableTraversableAmetysObject pluginNode = _getOrCreateNode(pluginsNode, __PLUGIN_NODE_NAME, "ametys:unstructured"); 754 755 return _getOrCreateNode(pluginNode, "ametys:thesaurii", __ROOT_THESAURII_NODETYPE); 756 } 757 catch (AmetysRepositoryException e) 758 { 759 throw new AmetysRepositoryException("Unable to get the thesaurus root node", e); 760 } 761 } 762 763 /** 764 * Get or create a node 765 * @param parentNode the parent node 766 * @param nodeName the name of the node 767 * @param nodeType the type of the node 768 * @return The retrieved or created node 769 * @throws AmetysRepositoryException if an error occurs when manipulating the repository 770 */ 771 protected ModifiableTraversableAmetysObject _getOrCreateNode(ModifiableTraversableAmetysObject parentNode, String nodeName, String nodeType) throws AmetysRepositoryException 772 { 773 ModifiableTraversableAmetysObject definitionsNode; 774 if (parentNode.hasChild(nodeName)) 775 { 776 definitionsNode = parentNode.getChild(nodeName); 777 } 778 else 779 { 780 definitionsNode = parentNode.createChild(nodeName, nodeType); 781 parentNode.saveChanges(); 782 } 783 return definitionsNode; 784 } 785}