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