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(rights = "Thesaurus_Rights_AccessThesaurus", context = "/cms") 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 public List<String> getMicrothesaurii() 170 { 171 List<String> microthesauriiList = new ArrayList<>(); 172 AmetysObjectIterable<Thesaurus> thesaurii = getThesaurii(); 173 for (Thesaurus thesaurus: thesaurii) 174 { 175 List<String> microthesaurii = getMicrothesaurii(thesaurus.getId()); 176 microthesauriiList.addAll(microthesaurii); 177 } 178 179 return microthesauriiList; 180 } 181 182 /** 183 * Get the parent thesaurus 184 * @param microThesaurus The microthesaurus 185 * @return the parent thesaurus 186 */ 187 public Thesaurus getParentThesaurus (ContentType microThesaurus) 188 { 189 AmetysObjectIterable<Thesaurus> thesaurii = getThesaurii(); 190 for (Thesaurus thesaurus : thesaurii) 191 { 192 if (thesaurus.getMicrothesaurii().contains(microThesaurus.getId())) 193 { 194 return thesaurus; 195 } 196 } 197 198 return null; 199 } 200 201 /** 202 * Get the contentTypeDefinition for a microthesaurus 203 * @param cTypeId The id of content type for this microthesaurus 204 * @param label The label of the microthesaurus 205 * @param parentThesaurus The parent thesaurus 206 * @return The ContentTypeDefinition of the reference table content type 207 */ 208 private ContentTypeDefinition _getMicrothesaurusContentTypeDefinition(String cTypeId, String label, Thesaurus parentThesaurus) 209 { 210 ContentTypeDefinition cTypeDef = new ContentTypeDefinition(cTypeId); 211 212 cTypeDef.setPluginName(_pluginName); 213 cTypeDef.setLabel(new I18nizableText(label)); 214 cTypeDef.setDescription(new I18nizableText(label)); 215 cTypeDef.setDefaultTitle(new I18nizableText("plugin." + _pluginName, "PLUGINS_THESAURUS_CONTENT_TYPE_TERM_DEFAULT_TITLE")); 216 cTypeDef.setCategory(new I18nizableText(parentThesaurus.getLabel())); 217 cTypeDef.setIconGlyph("ametysicon-letter-a"); 218 cTypeDef.setSupertypeIds(new String[] {MICROTHESAURUS_ABSTRACT_CONTENT_TYPE}); 219 220 // Set tags 221 cTypeDef.setTagsInherited(true); 222 223 // Additional model items 224 List<ModelItem> modelItems = _getModelItems(cTypeId); 225 cTypeDef.setModelItems(modelItems); 226 cTypeDef.setParentRef(METADATA_GENERIC_TERM); 227 228 // Do not override metadatasets from the supertypTerm 229 cTypeDef.setViews(ListUtils.EMPTY_LIST); 230 231 return cTypeDef; 232 } 233 234 /** 235 * Get the additional metadata for a microthesaurus 236 * @param microthesaurusCTypeId The id of content type for this microthesaurus 237 * @return The list of additional metadata definition 238 */ 239 private List<ModelItem> _getModelItems(String microthesaurusCTypeId) 240 { 241 List<ModelItem> modelItems = new ArrayList<>(); 242 ModelItemType contentAttributeType = _contentAttributeTypeExtensionPoint.getExtension(ModelItemTypeConstants.CONTENT_ELEMENT_TYPE_ID); 243 244 // Generic term 245 ContentAttributeDefinition genericTerm = new ContentAttributeDefinition(_contentTypeEP, _contentTypesHelper); 246 genericTerm.setContentTypeId(microthesaurusCTypeId); 247 genericTerm.setName(METADATA_GENERIC_TERM); 248 genericTerm.setMultiple(false); 249 genericTerm.setType(contentAttributeType); 250 genericTerm.setInvertRelationPath(METADATA_SPECIFIC_TERMS); 251 genericTerm.setLabel(new I18nizableText("plugin." + _pluginName, "PLUGINS_THESAURUS_CONTENT_TYPE_TERM_GENERIC_TERMS")); 252 genericTerm.setDescription(new I18nizableText("plugin." + _pluginName, "PLUGINS_THESAURUS_CONTENT_TYPE_TERM_GENERIC_TERMS_DESC")); 253 modelItems.add(genericTerm); 254 255 // Specific terms 256 ContentAttributeDefinition specificTerms = new ContentAttributeDefinition(_contentTypeEP, _contentTypesHelper); 257 specificTerms.setContentTypeId(microthesaurusCTypeId); 258 specificTerms.setName(METADATA_SPECIFIC_TERMS); 259 specificTerms.setMultiple(true); 260 specificTerms.setType(contentAttributeType); 261 specificTerms.setInvertRelationPath(METADATA_GENERIC_TERM); 262 specificTerms.setLabel(new I18nizableText("plugin." + _pluginName, "PLUGINS_THESAURUS_CONTENT_TYPE_TERM_SPECIFIC_TERMS")); 263 specificTerms.setDescription(new I18nizableText("plugin." + _pluginName, "PLUGINS_THESAURUS_CONTENT_TYPE_TERM_SPECIFIC_TERMS_DESC")); 264 modelItems.add(specificTerms); 265 266 // Related terms 267 ContentAttributeDefinition relatedTerms = new ContentAttributeDefinition(_contentTypeEP, _contentTypesHelper); 268 relatedTerms.setContentTypeId(microthesaurusCTypeId); 269 relatedTerms.setName(METADATA_RELATED_TERMS); 270 relatedTerms.setMultiple(true); 271 relatedTerms.setType(contentAttributeType); 272 relatedTerms.setInvertRelationPath(METADATA_RELATED_TERMS); 273 relatedTerms.setLabel(new I18nizableText("plugin." + _pluginName, "PLUGINS_THESAURUS_CONTENT_TYPE_TERM_RELATED_TERMS")); 274 relatedTerms.setDescription(new I18nizableText("plugin." + _pluginName, "PLUGINS_THESAURUS_CONTENT_TYPE_TERM_RELATED_TERMS_DESC")); 275 modelItems.add(relatedTerms); 276 277 return modelItems; 278 } 279 280 /** 281 * Get a thesaurus by its label 282 * @param label the label 283 * @return the thesaurus or null if not found 284 */ 285 public Thesaurus findThesaurusByLabel(String label) 286 { 287 String xpathQuery = "//element(*, " + ThesaurusFactory.THESAURUS_NODETYPE + ")[@ametys-internal:label='" + label + "']"; 288 289 AmetysObjectIterable<Thesaurus> thesaurii = _resolver.query(xpathQuery); 290 return thesaurii.getSize() > 0 ? thesaurii.iterator().next() : null; 291 } 292 293 /** 294 * Creates a thesaurus 295 * @param label The label 296 * @return The id and label of the created microthesaurus 297 */ 298 @Callable(rights = "Thesaurus_Rights_CreateThesaurus", context = "/cms") 299 public Map<String, Object> createThesaurus (String label) 300 { 301 Map<String, Object> result = new HashMap<>(); 302 303 if (findThesaurusByLabel(label) != null) 304 { 305 result.put("success", false); 306 result.put("alreadyExist", true); 307 result.put("label", label); 308 return result; 309 } 310 311 ModifiableTraversableAmetysObject rootNode = getRootNode(); 312 String originalName = NameHelper.filterName(label); 313 314 // Find unique name 315 int index = 2; 316 String name = originalName; 317 while (rootNode.hasChild(name)) 318 { 319 name = originalName + "_" + (index++); 320 } 321 322 Thesaurus thesaurus = rootNode.createChild(name, ThesaurusFactory.THESAURUS_NODETYPE); 323 thesaurus.setLabel(label); 324 325 rootNode.saveChanges(); 326 327 result.put("success", true); 328 result.put("id", thesaurus.getId()); 329 result.put("label", thesaurus.getLabel()); 330 result.put("canCreateMicroThesaurus", _rightManager.currentUserHasRight("Thesaurus_Rights_EditMicrothesaurus", "/cms") == RightResult.RIGHT_ALLOW); 331 332 return result; 333 } 334 335 /** 336 * Updates a thesaurus 337 * @param thesaurusId The id of microthesaurus 338 * @param label The new label 339 * @return The id and label of the updated microthesaurus 340 * @throws EditContentTypeException if failed to update the existing content types for child microthesaurii. 341 */ 342 @Callable(rights = "Thesaurus_Rights_EditThesaurus", context = "/cms") 343 public Map<String, Object> updateThesaurus (String thesaurusId, String label) throws EditContentTypeException 344 { 345 Map<String, Object> result = new HashMap<>(); 346 Thesaurus thesaurus = _resolver.resolveById(thesaurusId); 347 348 Thesaurus homonym = findThesaurusByLabel(label); 349 if (homonym != null && !homonym.equals(thesaurus)) 350 { 351 result.put("success", false); 352 result.put("alreadyExist", true); 353 result.put("label", label); 354 return result; 355 } 356 357 // Update category of existing microthesaurii content type 358 Collection<String> microthesaurii = thesaurus.getMicrothesaurii(); 359 if (microthesaurii.size() > 0) 360 { 361 result.put("hasMicrothesaurii", true); 362 for (String microthesaurus: microthesaurii) 363 { 364 ContentType contentType = _contentTypeEP.getExtension(microthesaurus); 365 366 ContentTypeDefinition contentTypeDef = _getMicrothesaurusContentTypeDefinition(contentType.getId(), contentType.getLabel().getLabel(), thesaurus); 367 contentTypeDef.setCategory(new I18nizableText(label)); 368 _editContentTypeHelper.editContentType(contentTypeDef); 369 } 370 } 371 372 thesaurus.setLabel(label); 373 thesaurus.saveChanges(); 374 375 result.put("success", true); 376 result.put("id", thesaurus.getId()); 377 result.put("label", thesaurus.getLabel()); 378 379 return result; 380 } 381 382 /** 383 * Deletes a thesaurus 384 * @param thesaurusId The id of thesaurus 385 * @return The id of the deleted thesaurus 386 */ 387 @Callable(rights = "Thesaurus_Rights_EditThesaurus", context = "/cms") 388 public Map<String, Object> deleteThesaurus (String thesaurusId) 389 { 390 Map<String, Object> result = new HashMap<>(); 391 392 Thesaurus thesaurus = _resolver.resolveById(thesaurusId); 393 List<String> microthesaurii = thesaurus.getMicrothesaurii(); 394 395 for (String microthesaurusId : microthesaurii) 396 { 397 Map<String, Object> checkResult = checkBeforeMicrothesaurusDeletion(microthesaurusId); 398 boolean checkMicrothesaurusOk = (boolean) checkResult.get("success"); 399 if (!checkMicrothesaurusOk) 400 { 401 result.putAll(checkResult); 402 403 ContentType cType = _contentTypeEP.getExtension(microthesaurusId); 404 405 Map<String, Object> microthesaurusParams = new HashMap<>(); 406 microthesaurusParams.put("id", microthesaurusId); 407 microthesaurusParams.put("label", cType.getLabel()); 408 409 result.put("undeletable-microthesaurus", microthesaurusParams); 410 return result; 411 } 412 } 413 414 415 result.put("id", thesaurus.getId()); 416 result.put("deleted-microthesaurii", new ArrayList<>()); 417 418 // Delete microthesaurus first 419 for (String microthesaurusId : microthesaurii) 420 { 421 ContentType cType = _contentTypeEP.getExtension(microthesaurusId); 422 423 Map<String, Object> microthesaurusParams = new HashMap<>(); 424 microthesaurusParams.put("id", microthesaurusId); 425 microthesaurusParams.put("label", cType.getLabel()); 426 427 Map<String, Object> deletionResult = deleteMicrothesaurus(microthesaurusId); 428 boolean deletionOk = (boolean) deletionResult.get("success"); 429 430 if (!deletionOk) 431 { 432 result.put("success", false); 433 result.put("undeleted-microthesaurus", microthesaurusParams); 434 return result; 435 } 436 else 437 { 438 @SuppressWarnings("unchecked") 439 List<Map<String, Object>> deletedMT = (List<Map<String, Object>>) result.get("deleted-microthesaurii"); 440 deletedMT.add(microthesaurusParams); 441 } 442 } 443 444 // Delete thesaurus 445 thesaurus.remove(); 446 thesaurus.saveChanges(); 447 448 result.put("success", true); 449 return result; 450 } 451 452 /** 453 * Get the label of thesaurus 454 * @param thesaurusId The id of thesaurus 455 * @return The id and label of the thesaurus 456 */ 457 @Callable(rights = "Thesaurus_Rights_AccessThesaurus", context = "/cms") 458 public String getThesaurusLabel (String thesaurusId) 459 { 460 Thesaurus thesaurus = _resolver.resolveById(thesaurusId); 461 return thesaurus.getLabel(); 462 } 463 464 /** 465 * Get the all terms of a microthesaurus 466 * @param microthesaurusId the id of microthesaurus 467 * @return all terms 468 */ 469 public AmetysObjectIterable<Content> getAllTerms(String microthesaurusId) 470 { 471 Expression cTypeExpr = new ContentTypeExpression(Operator.EQ, microthesaurusId); 472 String xPathQuery = ContentQueryHelper.getContentXPathQuery(cTypeExpr); 473 474 AmetysObjectIterable<Content> terms = _resolver.query(xPathQuery); 475 return terms; 476 } 477 478 /** 479 * Get the root terms of a microthesaurus 480 * @param microthesaurusId the id of microthesaurus 481 * @return root terms 482 */ 483 public AmetysObjectIterable<Content> getRootTerms(String microthesaurusId) 484 { 485 Expression cTypeExpr = new ContentTypeExpression(Operator.EQ, microthesaurusId); 486 Expression genericExpr = new NotExpression(new MetadataExpression(METADATA_GENERIC_TERM)); 487 String xPathQuery = ContentQueryHelper.getContentXPathQuery(new AndExpression(cTypeExpr, genericExpr)); 488 489 AmetysObjectIterable<Content> terms = _resolver.query(xPathQuery); 490 return terms; 491 } 492 493 /** 494 * Get direct child terms of a term 495 * @param microthesaurusId the id of microthesaurus 496 * @param parentId The parent Id 497 * @return The child terms 498 */ 499 public AmetysObjectIterable<Content> getChildTerms(String microthesaurusId, String parentId) 500 { 501 Expression cTypeExpr = new ContentTypeExpression(Operator.EQ, microthesaurusId); 502 Expression genericExpr = new StringExpression(METADATA_GENERIC_TERM, Operator.EQ, parentId); 503 String xPathQuery = ContentQueryHelper.getContentXPathQuery(new AndExpression(cTypeExpr, genericExpr)); 504 505 AmetysObjectIterable<Content> terms = _resolver.query(xPathQuery); 506 return terms; 507 } 508 509 /** 510 * Determines if a term which belongs to a microthesaurus is referenced by contents outside the microthesaurus 511 * @param microthesaurusId the id of microthesaurus 512 * @param term the content term 513 * @return true if the term has at least one referencing content outside the microthesaurus 514 */ 515 public boolean hasReferencingContents(String microthesaurusId, Content term) 516 { 517 Collection<Content> referencingContents = term.getReferencingContents(); 518 519 for (Content referencingContent : referencingContents) 520 { 521 if (!ArrayUtils.contains(referencingContent.getTypes(), microthesaurusId)) 522 { 523 return true; 524 } 525 } 526 527 return false; 528 } 529 530 /** 531 * Creates a microthesaurus 532 * @param label The label 533 * @param thesaurusId The id of parent thesaurus 534 * @param microthesaurusName the name of the microthesaurus 535 * @return The id and label of the created microthesaurus 536 * @throws EditContentTypeException if failed to create the microthesaurus content type 537 */ 538 @Callable(rights = {"Thesaurus_Rights_EditMicrothesaurus"}, context = "/cms") 539 public Map<String, Object> createMicrothesaurus (String label, String thesaurusId, String microthesaurusName) throws EditContentTypeException 540 { 541 Thesaurus thesaurus = _resolver.resolveById(thesaurusId); 542 543 Map<String, Object> result = new HashMap<>(); 544 545 String cTypeId = MICROTHESAURUS_CONTENT_TYPE_PREFIX + microthesaurusName; 546 547 List<String> microthesaurii = getMicrothesaurii(); 548 549 // Check if microthesaurus does not already exist 550 if (microthesaurii.contains(cTypeId)) 551 { 552 result.put("success", false); 553 result.put("alreadyExist", microthesaurusName); 554 555 int index = 2; 556 while (microthesaurii.contains(cTypeId)) 557 { 558 cTypeId = MICROTHESAURUS_CONTENT_TYPE_PREFIX + microthesaurusName + "-" + index; 559 index++; 560 } 561 562 result.put("suggestedName", StringUtils.substringAfter(cTypeId, MICROTHESAURUS_CONTENT_TYPE_PREFIX)); 563 return result; 564 } 565 566 // Create content type 567 ContentTypeDefinition contentType = _getMicrothesaurusContentTypeDefinition(cTypeId, label, thesaurus); 568 _editContentTypeHelper.createContentType(contentType); 569 570 thesaurus.addMicrothesaurus(cTypeId); 571 thesaurus.saveChanges(); 572 573 result.put("success", true); 574 result.put("id", microthesaurusName); 575 result.put("label", label); 576 result.put("thesaurusId", thesaurusId); 577 578 return result; 579 } 580 581 /** 582 * Edit a microthesaurus 583 * @param microthesaurusId The id of microthesaurus to edit 584 * @param label The new label 585 * @return The id and label of the updated microthesaurus 586 * @throws EditContentTypeException if failed to update the content type for this microthesaurus 587 */ 588 @Callable(rights = "Thesaurus_Rights_EditMicrothesaurus", context = "/cms") 589 public Map<String, Object> updateMicrothesaurus (String microthesaurusId, String label) throws EditContentTypeException 590 { 591 ContentType microThesaurus = _contentTypeEP.getExtension(microthesaurusId); 592 593 Thesaurus thesaurus = getParentThesaurus(microThesaurus); 594 595 // Update content type 596 ContentTypeDefinition contentTypeDef = _getMicrothesaurusContentTypeDefinition(microThesaurus.getId(), label, thesaurus); 597 _editContentTypeHelper.editContentType(contentTypeDef); 598 599 Map<String, Object> result = new HashMap<>(); 600 result.put("id", microThesaurus.getId()); 601 result.put("label", microThesaurus.getLabel()); 602 result.put("thesaurusId", thesaurus.getId()); 603 result.put("success", true); 604 605 return result; 606 } 607 608 /** 609 * Do some check before microthesaurus deletion 610 * @param microthesaurusId the id of microthesaurus 611 * @return the check result 612 */ 613 public Map<String, Object> checkBeforeMicrothesaurusDeletion(String microthesaurusId) 614 { 615 Map<String, Object> result = new HashMap<>(); 616 617 AmetysObjectIterable<Content> terms = getAllTerms(microthesaurusId); 618 if (terms.getSize() == 0) 619 { 620 result.put("success", true); 621 result.put("emptyMicrothesaurus", true); 622 return result; 623 } 624 625 for (Content term : terms) 626 { 627 if (hasReferencingContents(microthesaurusId, term)) 628 { 629 result.put("success", false); 630 result.put("hasReferencingContents", true); 631 return result; 632 } 633 } 634 635 result.put("success", true); 636 return result; 637 } 638 639 /** 640 * Deletes a microthesaurus 641 * @param microthesaurusId The id of microthesaurus 642 * @return The id of the deleted microthesaurus 643 */ 644 @Callable(rights = "Thesaurus_Rights_EditMicrothesaurus", context = "/cms") 645 public Map<String, Object> deleteMicrothesaurus(String microthesaurusId) 646 { 647 Map<String, Object> result = checkBeforeMicrothesaurusDeletion(microthesaurusId); 648 649 boolean checkOk = (boolean) result.get("success"); 650 if (!checkOk) 651 { 652 return result; 653 } 654 655 // Remove existing terms 656 AmetysObjectIterable<Content> terms = getAllTerms(microthesaurusId); 657 for (Content term : terms) 658 { 659 _deleteTerm(term); 660 } 661 662 ContentType cType = _contentTypeEP.getExtension(microthesaurusId); 663 Thesaurus thesaurus = getParentThesaurus(cType); 664 665 result.put("thesaurusId", thesaurus.getId()); 666 result.put("id", microthesaurusId); 667 result.put("label", cType.getLabel()); 668 669 try 670 { 671 _editContentTypeHelper.removeContentType(microthesaurusId); 672 } 673 catch (RemoveContentTypeException e) 674 { 675 getLogger().error("The microthesaurus with id {} can not be removed", microthesaurusId, e); 676 result.put("success", false); 677 678 return result; 679 } 680 681 // Remove thesaurus from parent thesaurus 682 thesaurus.removeMicrothesaurus(microthesaurusId); 683 thesaurus.saveChanges(); 684 685 result.put("success", true); 686 687 return result; 688 } 689 690 private void _deleteTerm (Content term) 691 { 692 Map<String, Object> eventParams = new HashMap<>(); 693 eventParams.put(ObservationConstants.ARGS_CONTENT, term); 694 eventParams.put(ObservationConstants.ARGS_CONTENT_NAME, term.getName()); 695 eventParams.put(ObservationConstants.ARGS_CONTENT_ID, term.getId()); 696 697 _observationManager.notify(new Event(ObservationConstants.EVENT_CONTENT_DELETING, _currentUserProvider.getUser(), eventParams)); 698 699 RemovableAmetysObject removableContent = (RemovableAmetysObject) term; 700 701 // Remove the content. 702 removableContent.remove(); 703 704 _observationManager.notify(new Event(ObservationConstants.EVENT_CONTENT_DELETED, _currentUserProvider.getUser(), eventParams)); 705 } 706 /** 707 * Get the root plugin storage object. 708 * @return the root plugin storage object. 709 * @throws AmetysRepositoryException if a repository error occurs. 710 */ 711 public ModifiableTraversableAmetysObject getRootNode() throws AmetysRepositoryException 712 { 713 try 714 { 715 ModifiableTraversableAmetysObject pluginsNode = _resolver.resolveByPath("/ametys:plugins"); 716 717 ModifiableTraversableAmetysObject pluginNode = _getOrCreateNode(pluginsNode, __PLUGIN_NODE_NAME, "ametys:unstructured"); 718 719 return _getOrCreateNode(pluginNode, "ametys:thesaurii", __ROOT_THESAURII_NODETYPE); 720 } 721 catch (AmetysRepositoryException e) 722 { 723 throw new AmetysRepositoryException("Unable to get the thesaurus root node", e); 724 } 725 } 726 727 /** 728 * Get or create a node 729 * @param parentNode the parent node 730 * @param nodeName the name of the node 731 * @param nodeType the type of the node 732 * @return The retrieved or created node 733 * @throws AmetysRepositoryException if an error occurs when manipulating the repository 734 */ 735 protected ModifiableTraversableAmetysObject _getOrCreateNode(ModifiableTraversableAmetysObject parentNode, String nodeName, String nodeType) throws AmetysRepositoryException 736 { 737 ModifiableTraversableAmetysObject definitionsNode; 738 if (parentNode.hasChild(nodeName)) 739 { 740 definitionsNode = parentNode.getChild(nodeName); 741 } 742 else 743 { 744 definitionsNode = parentNode.createChild(nodeName, nodeType); 745 parentNode.saveChanges(); 746 } 747 return definitionsNode; 748 } 749}