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