001/* 002 * Copyright 2013 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.cart; 017 018import java.time.ZonedDateTime; 019import java.util.ArrayList; 020import java.util.Collections; 021import java.util.HashSet; 022import java.util.List; 023import java.util.Set; 024import java.util.stream.Collectors; 025 026import javax.jcr.Node; 027import javax.jcr.RepositoryException; 028 029import org.apache.commons.lang3.ArrayUtils; 030import org.slf4j.Logger; 031import org.slf4j.LoggerFactory; 032 033import org.ametys.cms.data.ametysobject.ModifiableModelAwareDataAwareAmetysObject; 034import org.ametys.cms.data.holder.ModifiableIndexableDataHolder; 035import org.ametys.cms.data.holder.impl.DefaultModifiableModelAwareDataHolder; 036import org.ametys.cms.indexing.solr.SolrAclCacheUninfluentialObject; 037import org.ametys.cms.repository.Content; 038import org.ametys.core.user.UserIdentity; 039import org.ametys.plugins.explorer.resources.Resource; 040import org.ametys.plugins.queriesdirectory.Query; 041import org.ametys.plugins.repository.AmetysObject; 042import org.ametys.plugins.repository.AmetysRepositoryException; 043import org.ametys.plugins.repository.UnknownAmetysObjectException; 044import org.ametys.plugins.repository.data.holder.group.ModifiableModelAwareRepeater; 045import org.ametys.plugins.repository.data.holder.group.ModifiableModelAwareRepeaterEntry; 046import org.ametys.plugins.repository.data.repositorydata.impl.JCRRepositoryData; 047import org.ametys.plugins.repository.jcr.DefaultAmetysObject; 048 049/** 050 * Class representing a cart, backed by a JCR node.<br> 051 */ 052@SolrAclCacheUninfluentialObject 053public class Cart extends DefaultAmetysObject<CartFactory> implements ModifiableModelAwareDataAwareAmetysObject 054{ 055 /** Property name for cart title */ 056 public static final String TITLE = "label"; 057 /** Property name for cart description */ 058 public static final String DESCRIPTION = "description"; 059 /** Property name for cart documentation */ 060 public static final String DOCUMENTATION = "documentation"; 061 /** Property name for cart author */ 062 public static final String AUTHOR = "author"; 063 /** Property name for cart last contributor */ 064 public static final String CONTRIBUTOR = "contributor"; 065 /** Property name for cart creation date */ 066 public static final String CREATIONDATE = "creationDate"; 067 /** Property name for cart last modification date */ 068 public static final String LASTMODIFICATIONDATE = "lastModificationDate"; 069 070 /** Property name for cart content elements */ 071 public static final String CONTENT_CART_ELEMENTS = "contents"; 072 /** Property name for cart resource elements */ 073 public static final String RESOURCE_CART_ELEMENTS = "resources"; 074 /** Property name for cart queries elements */ 075 public static final String QUERIES_CART_ELEMENTS = "queries"; 076 /** Property name for cart queries from directory elements */ 077 public static final String QUERIES_FROM_DIRECTORY_CART_ELEMENTS = "queries-from-directory"; 078 079 /** Property name for cart query id */ 080 public static final String QUERY_ID_PROPERTY = "id"; 081 /** Property name for cart query description */ 082 public static final String QUERY_DESCRIPTION_PROPERTY = "description"; 083 /** Property name for cart query author */ 084 public static final String QUERY_AUTHOR_PROPERTY = "author"; 085 /** Property name for cart query title */ 086 public static final String QUERY_TITLE_PROPERTY = "title"; 087 /** Property name for cart query creation date */ 088 public static final String QUERY_DATE_PROPERTY = "date"; 089 090 private static Logger _logger = LoggerFactory.getLogger(Cart.class.getName()); 091 092 /** 093 * Rights profiles 094 */ 095 public enum CartProfile 096 { 097 /** Read access */ 098 READ_ACCESS, 099 /** Write access */ 100 WRITE_ACCESS, 101 /** Right access */ 102 RIGHT_ACCESS; 103 104 @Override 105 public String toString() 106 { 107 return name().toLowerCase(); 108 } 109 } 110 111 /** 112 * Types of CartElement 113 */ 114 public enum CartElementType 115 { 116 /** Type: content. */ 117 CONTENT, 118 /** Type: resource. */ 119 RESOURCE, 120 /** Type: cartQuery. */ 121 CARTQUERY, 122 /** Type: query from directory. */ 123 CARTQUERYFROMDIRECTORY 124 } 125 126 /** 127 * Creates an {@link Cart}. 128 * @param node the node backing this {@link AmetysObject} 129 * @param parentPath the parentPath in the Ametys hierarchy 130 * @param factory the DefaultAmetysObjectFactory which created the AmetysObject 131 */ 132 public Cart(Node node, String parentPath, CartFactory factory) 133 { 134 super(node, parentPath, factory); 135 } 136 137 /** 138 * Set the title of this cart. 139 * @param title the title 140 */ 141 public void setTitle(String title) 142 { 143 this.setValue(TITLE, title); 144 } 145 146 /** 147 * Set the description of this cart. 148 * @param description the description 149 */ 150 public void setDescription(String description) 151 { 152 this.setValue(DESCRIPTION, description); 153 } 154 155 /** 156 * Set the documentation of this cart. 157 * @param documentation the documentation 158 */ 159 public void setDocumentation(String documentation) 160 { 161 this.setValue(DOCUMENTATION, documentation); 162 } 163 164 /** 165 * Set the author of this cart. 166 * @param author the author 167 */ 168 public void setAuthor(UserIdentity author) 169 { 170 this.setValue(AUTHOR, author); 171 } 172 173 /** 174 * Set the last contributor of this cart. 175 * @param contributor the last contributor 176 */ 177 public void setContributor(UserIdentity contributor) 178 { 179 this.setValue(CONTRIBUTOR, contributor); 180 } 181 182 /** 183 * Set the date of the creation. 184 * @param creationDate the last modification date to set. 185 */ 186 public void setCreationDate(ZonedDateTime creationDate) 187 { 188 this.setValue(CREATIONDATE, creationDate); 189 } 190 191 /** 192 * Set the date of the last modification. 193 * @param lastModificationDate the last modification date to set. 194 */ 195 public void setLastModificationDate(ZonedDateTime lastModificationDate) 196 { 197 this.setValue(LASTMODIFICATIONDATE, lastModificationDate); 198 } 199 200 /** 201 * Get the title of the cart 202 * @return The title 203 */ 204 public String getTitle() 205 { 206 return this.getValue(TITLE); 207 } 208 209 /** 210 * Get the description of the cart 211 * @return The description 212 */ 213 public String getDescription() 214 { 215 return this.getValue(DESCRIPTION); 216 } 217 218 /** 219 * Get the documentation of the cart 220 * @return The documentation 221 */ 222 public String getDocumentation() 223 { 224 return this.getValue(DOCUMENTATION); 225 } 226 227 /** 228 * Get the author of the cart 229 * @return The author 230 */ 231 public UserIdentity getAuthor() 232 { 233 return this.getValue(AUTHOR); 234 } 235 236 /** 237 * Get the last contributor of the cart 238 * @return The contributor 239 */ 240 public UserIdentity getContributor() 241 { 242 return this.getValue(CONTRIBUTOR); 243 } 244 245 /** 246 * Get the date of the last modification of the cart 247 * @return The date 248 */ 249 public ZonedDateTime getCreationDate() 250 { 251 return this.getValue(CREATIONDATE); 252 } 253 254 /** 255 * Get the date of the last modification of the cart 256 * @return The date 257 */ 258 public ZonedDateTime getLastModificationDate() 259 { 260 return this.getValue(LASTMODIFICATIONDATE); 261 } 262 263 /** 264 * Add a content to the cart 265 * @param contentId The content id 266 */ 267 public void addContent (String contentId) 268 { 269 _addElementToCart(contentId, CONTENT_CART_ELEMENTS); 270 } 271 272 /** 273 * Add a resource to the cart 274 * @param resourceId The resource id 275 */ 276 public void addResource (String resourceId) 277 { 278 _addElementToCart(resourceId, RESOURCE_CART_ELEMENTS); 279 } 280 281 /** 282 * Add a query from directory to the cart 283 * @param queryId The query id 284 */ 285 public void addQueryFormDirectory (String queryId) 286 { 287 _addElementToCart(queryId, QUERIES_FROM_DIRECTORY_CART_ELEMENTS); 288 } 289 290 private void _addElementToCart(String elementId, String attributePath) 291 { 292 String[] elmtArray = getValue(attributePath, false, new String[0]); 293 Set<String> elmts = new HashSet<>(); 294 Collections.addAll(elmts, elmtArray); 295 elmts.add(elementId); 296 setValue(attributePath, elmts.toArray(new String[elmts.size()])); 297 } 298 299 /** 300 * Add a query to the cart 301 * @param author The author of the query 302 * @param title The title of the query 303 * @param description The query as string 304 */ 305 public void addQuery (UserIdentity author, String title, String description) 306 { 307 addQuery(org.ametys.core.util.StringUtils.generateKey(), author, title, description, ZonedDateTime.now()); 308 } 309 310 /** 311 * Add a query to the cart 312 * @param id The id of the query 313 * @param author The author of the query 314 * @param title The title of the query 315 * @param description The query as string 316 * @param date The creation date of the query 317 */ 318 public void addQuery (String id, UserIdentity author, String title, String description, ZonedDateTime date) 319 { 320 ModifiableModelAwareRepeater queries = getRepeater(QUERIES_CART_ELEMENTS, true); 321 ModifiableModelAwareRepeaterEntry query = queries.addEntry(); 322 query.setValue(QUERY_ID_PROPERTY, id); 323 query.setValue(QUERY_TITLE_PROPERTY, title); 324 query.setValue(QUERY_DESCRIPTION_PROPERTY, description); 325 query.setValue(QUERY_AUTHOR_PROPERTY, author); 326 query.setValue(QUERY_DATE_PROPERTY, date); 327 } 328 329 /** 330 * Delete an element 331 * @param elmtId The id of element to remove 332 * @param elmtType The type of element to remove 333 */ 334 public void removeElement (String elmtId, CartElementType elmtType) 335 { 336 switch (elmtType) 337 { 338 case CONTENT: 339 _removeContent(elmtId); 340 break; 341 342 case RESOURCE: 343 _removeResource(elmtId); 344 break; 345 346 case CARTQUERY: 347 _removeQuery(elmtId); 348 break; 349 350 case CARTQUERYFROMDIRECTORY: 351 _removeQueryFromDirectory(elmtId); 352 break; 353 354 default: 355 break; 356 } 357 } 358 359 /** 360 * Remove a resource from the cart 361 * @param resourceIdToRemove The id of the resource to remove 362 */ 363 protected void _removeResource(String resourceIdToRemove) 364 { 365 _removeElementFromCart(resourceIdToRemove, RESOURCE_CART_ELEMENTS); 366 } 367 368 /** 369 * Remove a content from the cart 370 * @param contentIdToRemove The id of the content to remove 371 */ 372 protected void _removeContent(String contentIdToRemove) 373 { 374 _removeElementFromCart(contentIdToRemove, CONTENT_CART_ELEMENTS); 375 } 376 377 /** 378 * Remove a query from directory from the cart 379 * @param queryIdToRemove The id of the query from directory to remove 380 */ 381 protected void _removeQueryFromDirectory(String queryIdToRemove) 382 { 383 _removeElementFromCart(queryIdToRemove, QUERIES_FROM_DIRECTORY_CART_ELEMENTS); 384 } 385 386 private void _removeElementFromCart(String elementId, String attributePath) 387 { 388 String[] elements = getValue(attributePath, false, new String[0]); 389 elements = ArrayUtils.removeElement(elements, elementId); 390 setValue(attributePath, elements); 391 } 392 393 /** 394 * Remove a query from the cart 395 * @param queryIdToRemove The id of the query to remove 396 */ 397 protected void _removeQuery(String queryIdToRemove) 398 { 399 ModifiableModelAwareRepeater queries = getRepeater(QUERIES_CART_ELEMENTS, true); 400 ModifiableModelAwareRepeaterEntry entryToRemove = queries.getEntries() 401 .stream() 402 .filter(entry -> entry.getValue(QUERY_ID_PROPERTY).equals(queryIdToRemove)) 403 .findFirst() 404 .orElse(null); 405 406 if (entryToRemove != null) 407 { 408 queries.removeEntry(entryToRemove.getPosition()); 409 } 410 } 411 412 /** 413 * Get the elements of the cart 414 * @return The elements of the cart 415 */ 416 public List<CartElement> getElements () 417 { 418 List<CartElement> elmts = new ArrayList<>(); 419 420 try 421 { 422 elmts.addAll(getContentCartElements()); 423 elmts.addAll(getResourceCartElements()); 424 elmts.addAll(getQueryCartElements()); 425 elmts.addAll(getQueryFromDirectoryCartElements()); 426 } 427 catch (RepositoryException e) 428 { 429 throw new AmetysRepositoryException("Error while getting cart elements", e); 430 } 431 432 return elmts; 433 } 434 435 /** 436 * Get the contents of the cart 437 * @return The elements of the cart 438 * @throws RepositoryException if an exception occurs while exploring the repository 439 */ 440 public List<ContentElement> getContentCartElements () throws RepositoryException 441 { 442 List<String> unexistingElmts = new ArrayList<>(); 443 444 List<ContentElement> elmts = new ArrayList<>(); 445 446 String[] contents = getValue(CONTENT_CART_ELEMENTS, false, new String[0]); 447 448 for (String contentId : contents) 449 { 450 try 451 { 452 Content content = _getFactory().getResolver().resolveById(contentId); 453 elmts.add(new ContentElement(content, _getFactory()._getContentTypesHelper(), _getFactory()._getContentTypeEP())); 454 } 455 catch (UnknownAmetysObjectException e) 456 { 457 _logger.error("The content of id '{}' does not exist anymore. It will be deleting from cart '{}'.", contentId, getId()); 458 unexistingElmts.add(contentId); 459 } 460 } 461 // Delete unexisting contents 462 for (String contentId : unexistingElmts) 463 { 464 _removeContent(contentId); 465 } 466 467 return elmts; 468 } 469 470 /** 471 * Get the resources of the cart 472 * @return The elements of the cart 473 * @throws RepositoryException if an exception occurs while exploring the repository 474 */ 475 public List<ResourceElement> getResourceCartElements () throws RepositoryException 476 { 477 List<String> unexistingElmts = new ArrayList<>(); 478 List<ResourceElement> elmts = new ArrayList<>(); 479 480 481 String[] resources = getValue(RESOURCE_CART_ELEMENTS, false, new String[0]); 482 483 for (String resourceId : resources) 484 { 485 try 486 { 487 Resource resource = _getFactory().getResolver().resolveById(resourceId); 488 elmts.add(new ResourceElement(resource)); 489 } 490 catch (UnknownAmetysObjectException e) 491 { 492 _logger.error("The resource of id '{}' does not exist anymore. It will be deleting from cart '{}'.", resourceId, getId()); 493 unexistingElmts.add(resourceId); 494 } 495 } 496 497 // Delete unexisting resources 498 for (String resourceId : unexistingElmts) 499 { 500 _removeResource(resourceId); 501 } 502 503 return elmts; 504 } 505 506 /** 507 * Get the resources of the cart 508 * @return The elements of the cart 509 * @throws RepositoryException if an exception occurs while exploring the repository 510 */ 511 public List<QueryFromDirectoryElement> getQueryFromDirectoryCartElements () throws RepositoryException 512 { 513 List<String> unexistingElmts = new ArrayList<>(); 514 List<QueryFromDirectoryElement> elmts = new ArrayList<>(); 515 516 517 String[] queries = getValue(QUERIES_FROM_DIRECTORY_CART_ELEMENTS, false, new String[0]); 518 for (String queryId : queries) 519 { 520 try 521 { 522 Query query = _getFactory().getResolver().resolveById(queryId); 523 elmts.add(new QueryFromDirectoryElement(query)); 524 } 525 catch (UnknownAmetysObjectException e) 526 { 527 _logger.error("The query of id '{}' does not exist anymore. It will be deleting from cart '{}'.", queryId, getId()); 528 unexistingElmts.add(queryId); 529 } 530 } 531 532 // Delete unexisting queries 533 for (String queryId : unexistingElmts) 534 { 535 _removeQueryFromDirectory(queryId); 536 } 537 538 return elmts; 539 } 540 541 /** 542 * <code>true</code> if the query cart element exist 543 * @param queryId the query id 544 * @return <code>true</code> if the query cart element exist 545 */ 546 public boolean hasQueryFromDirectoryCartElement(String queryId) 547 { 548 String[] queries = getValue(QUERIES_FROM_DIRECTORY_CART_ELEMENTS, false, new String[0]); 549 return ArrayUtils.contains(queries, queryId); 550 } 551 552 /** 553 * Get the queries of the cart 554 * @return The elements of the cart 555 * @throws RepositoryException if an exception occurs while exploring the repository 556 */ 557 public List<QueryElement> getQueryCartElements () throws RepositoryException 558 { 559 ModifiableModelAwareRepeater queries = getRepeater(QUERIES_CART_ELEMENTS, true); 560 561 List<QueryElement> elmts = queries.getEntries() 562 .stream() 563 .map(entry -> { 564 String id = entry.getValue(QUERY_ID_PROPERTY); 565 UserIdentity author = entry.getValue(QUERY_AUTHOR_PROPERTY); 566 String query = entry.getValue(QUERY_DESCRIPTION_PROPERTY); 567 String title = entry.getValue(QUERY_TITLE_PROPERTY); 568 ZonedDateTime creationDate = entry.getValue(QUERY_DATE_PROPERTY); 569 570 return new QueryElement(id, query, author, creationDate, author, creationDate, title); 571 }) 572 .collect(Collectors.toList()); 573 574 return elmts; 575 } 576 577 public ModifiableIndexableDataHolder getDataHolder() 578 { 579 JCRRepositoryData repositoryData = new JCRRepositoryData(getNode()); 580 return new DefaultModifiableModelAwareDataHolder(repositoryData, this._getFactory().getModel()); 581 } 582}