001/* 002 * Copyright 2010 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 */ 016 017package org.ametys.cms.repository.comment; 018 019import java.util.ArrayList; 020import java.util.Date; 021import java.util.List; 022 023import org.ametys.cms.repository.ReactionableObjectHelper; 024import org.ametys.cms.repository.ReactionableObject; 025import org.ametys.core.user.UserIdentity; 026import org.ametys.plugins.repository.AmetysRepositoryException; 027import org.ametys.plugins.repository.metadata.ModifiableCompositeMetadata; 028 029/** 030 * A comment on a commentable content 031 */ 032public class Comment implements ReactionableObject 033{ 034 /** Constants for comments Metadat* */ 035 public static final String METADATA_COMMENTS = "comments"; 036 /** Constants for comments Metadata not validted */ 037 public static final String METADATA_COMMENTS_VALIDATED = "validated"; 038 /** Constants for comments Metadata validated */ 039 public static final String METADATA_COMMENTS_NOTVALIDATED = "not-validated"; 040 041 /** Constants for creation Metadata */ 042 public static final String METADATA_COMMENT_CREATIONDATE = "creation"; 043 /** Constants for author name Metadata */ 044 public static final String METADATA_COMMENT_AUTHORNAME = "author-name"; 045 /** Constants for author email Metadata */ 046 public static final String METADATA_COMMENT_AUTHOREMAIL = "author-email"; 047 /** Constants for author email hidden Metadata */ 048 public static final String METADATA_COMMENT_AUTHOREMAIL_HIDDEN = "author-email-hidden"; 049 /** Constants for author url Metadata */ 050 public static final String METADATA_COMMENT_AUTHORURL = "author-url"; 051 /** Constants for the content Metadata */ 052 public static final String METADATA_COMMENT_CONTENT = "content"; 053 /** Constants for the validated status Metadata */ 054 public static final String METADATA_COMMENT_VALIDATED = "validated"; 055 /** Constants for the number of reporters Metadata */ 056 public static final String METADATA_COMMENT_NB_REPORTERS = "nb-reporters"; 057 058 /** Constants for the separator */ 059 public static final String ID_SEPARATOR = "_"; 060 061 /** The content to comment */ 062 protected ModifiableCompositeMetadata _contentMetadataHolder; 063 /** The metadata node of the comment */ 064 protected ModifiableCompositeMetadata _metadata; 065 /** The id of the comment (unique in the content) */ 066 protected String _id; 067 068 /** 069 * Retrieves a comment by its id 070 * @param contentUnversionnedMetadataHolder The unversionned metadate holder of the content hosting the comment 071 * @param commentId The id of the comment to retrieve 072 * @throws AmetysRepositoryException if an error occured 073 */ 074 public Comment(ModifiableCompositeMetadata contentUnversionnedMetadataHolder, String commentId) 075 { 076 _contentMetadataHolder = contentUnversionnedMetadataHolder; 077 _id = commentId; 078 079 String[] commentIdAsTab = commentId.split(ID_SEPARATOR); 080 int i = 0; 081 ModifiableCompositeMetadata currentMetadataHolder = _contentMetadataHolder; 082 while (i < commentIdAsTab.length) 083 { 084 ModifiableCompositeMetadata commentsComposite = currentMetadataHolder.getCompositeMetadata(Comment.METADATA_COMMENTS); 085 currentMetadataHolder = commentsComposite.getCompositeMetadata(commentIdAsTab[i]); 086 i++; 087 } 088 089 _metadata = currentMetadataHolder; 090 } 091 092 /** 093 * Creates a new comment on the content 094 * @param contentUnversionnedMetadataHolder The unversionned metadate holder of the content where to add the new comment 095 */ 096 public Comment(ModifiableCompositeMetadata contentUnversionnedMetadataHolder) 097 { 098 _contentMetadataHolder = contentUnversionnedMetadataHolder; 099 100 ModifiableCompositeMetadata parent = _contentMetadataHolder.getCompositeMetadata(METADATA_COMMENTS, true); 101 102 String base = "comment-"; 103 int i = 0; 104 while (parent.hasMetadata(base + i)) 105 { 106 i++; 107 } 108 109 _id = base + i; 110 _metadata = _contentMetadataHolder.getCompositeMetadata(METADATA_COMMENTS, true).getCompositeMetadata(_id, true); 111 _metadata.setMetadata(METADATA_COMMENT_CREATIONDATE, new Date()); 112 113 update(); 114 } 115 116 /** 117 * Creates a new sub comment of the comment 118 * @param comment The parent comment 119 */ 120 public Comment(Comment comment) 121 { 122 _contentMetadataHolder = comment.getContentMetadata(); 123 124 ModifiableCompositeMetadata parent = comment.getMetadata().getCompositeMetadata(METADATA_COMMENTS, true); 125 126 String base = "comment-"; 127 int i = 0; 128 while (parent.hasMetadata(base + i)) 129 { 130 i++; 131 } 132 133 String commentName = base + i; 134 _id = comment.getId() + ID_SEPARATOR + commentName; 135 _metadata = parent.getCompositeMetadata(commentName, true); 136 _metadata.setMetadata(METADATA_COMMENT_CREATIONDATE, new Date()); 137 138 update(); 139 } 140 141 /** 142 * Get the composite metadata object holding the comment 143 * @return the composite metadata 144 */ 145 public ModifiableCompositeMetadata getMetadata() 146 { 147 return _metadata; 148 } 149 150 /** 151 * Get the composite metadata object holding the content 152 * @return the content composite metadata 153 */ 154 public ModifiableCompositeMetadata getContentMetadata() 155 { 156 return _contentMetadataHolder; 157 } 158 159 /** 160 * The comment id (unique to the content) 161 * @return The id. Cannot be null. 162 */ 163 public String getId() 164 { 165 return _id; 166 } 167 /** 168 * Get the date and time the comment was created 169 * @return The non null date of creation of the comment. 170 */ 171 public Date getCreationDate() 172 { 173 return _metadata.getDate(METADATA_COMMENT_CREATIONDATE); 174 } 175 176 /** 177 * Get the readable name of the author. 178 * @return The full name. Can be null. 179 */ 180 public String getAuthorName() 181 { 182 if (_metadata.hasMetadata(METADATA_COMMENT_AUTHORNAME)) 183 { 184 return _metadata.getString(METADATA_COMMENT_AUTHORNAME); 185 } 186 else 187 { 188 return null; 189 } 190 } 191 /** 192 * Set the readable name of the author. 193 * @param name The full name. Can be null to remove the name. 194 */ 195 public void setAuthorName(String name) 196 { 197 if (name != null) 198 { 199 _metadata.setMetadata(METADATA_COMMENT_AUTHORNAME, name); 200 } 201 else if (_metadata.hasMetadata(METADATA_COMMENT_AUTHORNAME)) 202 { 203 _metadata.removeMetadata(METADATA_COMMENT_AUTHORNAME); 204 } 205 } 206 207 /** 208 * Get the email of the author. 209 * @return The ameil. Can be null. 210 */ 211 public String getAuthorEmail() 212 { 213 if (_metadata.hasMetadata(METADATA_COMMENT_AUTHOREMAIL)) 214 { 215 return _metadata.getString(METADATA_COMMENT_AUTHOREMAIL); 216 } 217 else 218 { 219 return null; 220 } 221 } 222 /** 223 * Set the email of the author. 224 * @param email The email. Can be null to remove the email. 225 */ 226 public void setAuthorEmail(String email) 227 { 228 if (email != null) 229 { 230 _metadata.setMetadata(METADATA_COMMENT_AUTHOREMAIL, email); 231 } 232 else if (_metadata.hasMetadata(METADATA_COMMENT_AUTHOREMAIL)) 233 { 234 _metadata.removeMetadata(METADATA_COMMENT_AUTHOREMAIL); 235 } 236 } 237 238 /** 239 * Get the url given by the author as its personnal site url. 240 * @return The url. Can be null. 241 */ 242 public String getAuthorURL() 243 { 244 if (_metadata.hasMetadata(METADATA_COMMENT_AUTHORURL)) 245 { 246 return _metadata.getString(METADATA_COMMENT_AUTHORURL); 247 } 248 else 249 { 250 return null; 251 } 252 } 253 /** 254 * Set the personnal site url of the author 255 * @param url The url. Can be null to remove url. 256 */ 257 public void setAuthorURL(String url) 258 { 259 if (url != null) 260 { 261 _metadata.setMetadata(METADATA_COMMENT_AUTHORURL, url); 262 } 263 else if (_metadata.hasMetadata(METADATA_COMMENT_AUTHORURL)) 264 { 265 _metadata.removeMetadata(METADATA_COMMENT_AUTHORURL); 266 } 267 } 268 269 /** 270 * Does the email of the authors have to be hidden ? 271 * @return true (default value) if the email does not have to appears to others users. Can still be used for administration. 272 */ 273 public boolean isEmailHidden() 274 { 275 if (_metadata.hasMetadata(METADATA_COMMENT_AUTHOREMAIL_HIDDEN)) 276 { 277 return _metadata.getBoolean(METADATA_COMMENT_AUTHOREMAIL_HIDDEN); 278 } 279 else 280 { 281 return true; 282 } 283 } 284 /** 285 * Set the email hidden status. 286 * @param hideEmail true to set the email as hidden. 287 */ 288 public void setEmailHiddenStatus(boolean hideEmail) 289 { 290 _metadata.setMetadata(METADATA_COMMENT_AUTHOREMAIL_HIDDEN, hideEmail); 291 } 292 293 /** 294 * Get the content of the comment. A simple String (with \n or \t). 295 * @return The content. Can be null. 296 */ 297 public String getContent() 298 { 299 if (_metadata.hasMetadata(METADATA_COMMENT_CONTENT)) 300 { 301 return _metadata.getString(METADATA_COMMENT_CONTENT); 302 } 303 else 304 { 305 return null; 306 } 307 } 308 /** 309 * Set the content of the comment. 310 * @param content The content to set. Can be null to remove the content. Have to be a simple String (with \n or \t). 311 */ 312 public void setContent(String content) 313 { 314 if (content != null) 315 { 316 _metadata.setMetadata(METADATA_COMMENT_CONTENT, content); 317 } 318 else if (_metadata.hasMetadata(METADATA_COMMENT_CONTENT)) 319 { 320 _metadata.removeMetadata(METADATA_COMMENT_CONTENT); 321 } 322 } 323 324 /** 325 * Is the comment validated 326 * @return the status of validation of the comment 327 */ 328 public boolean isValidated() 329 { 330 if (_metadata.hasMetadata(METADATA_COMMENT_VALIDATED)) 331 { 332 return _metadata.getBoolean(METADATA_COMMENT_VALIDATED); 333 } 334 else 335 { 336 return false; 337 } 338 } 339 340 /** 341 * Set the validation status of the comment 342 * @param validated true the comment is validated 343 */ 344 public void setValidated(boolean validated) 345 { 346 _metadata.setMetadata(METADATA_COMMENT_VALIDATED, validated); 347 update(); 348 } 349 350 /** 351 * Reset to 0 the number of reporters 352 */ 353 public void resetNbReporters() 354 { 355 _metadata.setMetadata(METADATA_COMMENT_NB_REPORTERS, 0); 356 } 357 /** 358 * Increase the number of reporters 359 * @return the increase number of reporters 360 */ 361 public Long increaseNbReporters() 362 { 363 Long nbReporters = getNbReporters(); 364 365 Long nbReportersIncreased = nbReporters + 1; 366 _metadata.setMetadata(METADATA_COMMENT_NB_REPORTERS, nbReportersIncreased); 367 368 return nbReportersIncreased; 369 } 370 371 /** 372 * Get the number of reporters 373 * @return the number of reporters 374 */ 375 public Long getNbReporters() 376 { 377 return _metadata.getLong(METADATA_COMMENT_NB_REPORTERS, 0L); 378 } 379 380 /** 381 * Remove the comment. 382 */ 383 public void remove() 384 { 385 String[] commentIdAsTab = _id.split(ID_SEPARATOR); 386 int i = 0; 387 ModifiableCompositeMetadata currentMetadataHolder = _contentMetadataHolder; 388 int lastIndex = commentIdAsTab.length - 1; 389 while (i < lastIndex) 390 { 391 ModifiableCompositeMetadata commentsComposite = currentMetadataHolder.getCompositeMetadata(Comment.METADATA_COMMENTS); 392 currentMetadataHolder = commentsComposite.getCompositeMetadata(commentIdAsTab[i]); 393 i++; 394 } 395 currentMetadataHolder.getCompositeMetadata(Comment.METADATA_COMMENTS).removeMetadata(commentIdAsTab[lastIndex]); 396 update(); 397 } 398 399 /** 400 * Get sub comments of the comment 401 * @param includeNotValidatedComments True to include the comments that are not validated 402 * @param includeValidatedComments True to include the comments that are validated 403 * @return the list of comments 404 */ 405 public List<Comment> getSubComment(boolean includeNotValidatedComments, boolean includeValidatedComments) 406 { 407 return getComments(this, includeNotValidatedComments, includeValidatedComments); 408 } 409 410 /** 411 * Create sub comment from this comment 412 * @return the sub comment 413 */ 414 public Comment createSubComment() 415 { 416 return new Comment(this); 417 } 418 419 /** 420 * Update the comment tag statistics 421 */ 422 protected void update() 423 { 424 long validated = 0; 425 long notValidated = 0; 426 427 List<Comment> comments = getComments(_contentMetadataHolder, true, true, false); 428 429 for (Comment comment : comments) 430 { 431 if (comment.isValidated()) 432 { 433 validated++; 434 } 435 else 436 { 437 notValidated++; 438 } 439 } 440 441 _contentMetadataHolder.getCompositeMetadata(METADATA_COMMENTS).setMetadata(METADATA_COMMENTS_VALIDATED, validated); 442 _contentMetadataHolder.getCompositeMetadata(METADATA_COMMENTS).setMetadata(METADATA_COMMENTS_NOTVALIDATED, notValidated); 443 } 444 445 /** 446 * Get a comment 447 * @param contentUnversionnedMetadataHolder the content 448 * @param commentId The comment 449 * @return The comment 450 * @throws AmetysRepositoryException if the comment does not exist 451 */ 452 public static Comment getComment(ModifiableCompositeMetadata contentUnversionnedMetadataHolder, String commentId) throws AmetysRepositoryException 453 { 454 return new Comment(contentUnversionnedMetadataHolder, commentId); 455 } 456 457 /** 458 * Get the comments of a content 459 * @param parentComment The parent comment 460 * @param includeNotValidatedComments True to include the comments that are not validated 461 * @param includeValidatedComments True to include the comments that are validated 462 * @return the list of comments 463 * @throws AmetysRepositoryException If an error occurred 464 */ 465 public static List<Comment> getComments(Comment parentComment, boolean includeNotValidatedComments, boolean includeValidatedComments) throws AmetysRepositoryException 466 { 467 return getComments(parentComment, includeNotValidatedComments, includeValidatedComments, false); 468 } 469 470 /** 471 * Get the comments of a content 472 * @param parentComment The parent comment 473 * @param includeNotValidatedComments True to include the comments that are not validated 474 * @param includeValidatedComments True to include the comments that are validated 475 * @param withSubComment true if we want to get all child comments 476 * @return the list of comments 477 * @throws AmetysRepositoryException If an error occurred 478 */ 479 public static List<Comment> getComments(Comment parentComment, boolean includeNotValidatedComments, boolean includeValidatedComments, boolean withSubComment) throws AmetysRepositoryException 480 { 481 ModifiableCompositeMetadata parentUnversionnedMetadataHolder = parentComment.getMetadata(); 482 List<Comment> comments = new ArrayList<>(); 483 484 if (parentUnversionnedMetadataHolder.hasMetadata(METADATA_COMMENTS)) 485 { 486 String[] names = parentUnversionnedMetadataHolder.getCompositeMetadata(METADATA_COMMENTS).getMetadataNames(); 487 for (String name : names) 488 { 489 if (METADATA_COMMENTS_NOTVALIDATED.equals(name) || METADATA_COMMENTS_VALIDATED.equals(name)) 490 { 491 continue; 492 } 493 494 String id = parentComment.getId() + ID_SEPARATOR + name; 495 Comment c = new Comment(parentComment.getContentMetadata(), id); 496 if (includeNotValidatedComments && !c.isValidated() || includeValidatedComments && c.isValidated()) 497 { 498 comments.add(c); 499 if (withSubComment) 500 { 501 comments.addAll(getComments(c, includeNotValidatedComments, includeValidatedComments, withSubComment)); 502 } 503 } 504 } 505 } 506 507 return comments; 508 } 509 510 /** 511 * Get the comments of a content 512 * @param contentUnversionnedMetadataHolder The content unversionned metadata holder 513 * @param includeNotValidatedComments True to include the comments that are not validated 514 * @param includeValidatedComments True to include the comments that are validated 515 * @return the list of comments 516 * @throws AmetysRepositoryException If an error occurred 517 */ 518 public static List<Comment> getComments(ModifiableCompositeMetadata contentUnversionnedMetadataHolder, boolean includeNotValidatedComments, boolean includeValidatedComments) throws AmetysRepositoryException 519 { 520 return getComments(contentUnversionnedMetadataHolder, includeNotValidatedComments, includeValidatedComments, false); 521 } 522 523 /** 524 * Get the comments of a content 525 * @param contentUnversionnedMetadataHolder The content unversionned metadata holder 526 * @param includeNotValidatedComments True to include the comments that are not validated 527 * @param includeValidatedComments True to include the comments that are validated 528 * @param isRecursive true if we want to have sub comments 529 * @return the list of comments 530 * @throws AmetysRepositoryException If an error occurred 531 */ 532 public static List<Comment> getComments(ModifiableCompositeMetadata contentUnversionnedMetadataHolder, boolean includeNotValidatedComments, boolean includeValidatedComments, boolean isRecursive) throws AmetysRepositoryException 533 { 534 List<Comment> comments = new ArrayList<>(); 535 536 if (contentUnversionnedMetadataHolder.hasMetadata(METADATA_COMMENTS)) 537 { 538 String[] ids = contentUnversionnedMetadataHolder.getCompositeMetadata(METADATA_COMMENTS).getMetadataNames(); 539 for (String id : ids) 540 { 541 if (METADATA_COMMENTS_NOTVALIDATED.equals(id) || METADATA_COMMENTS_VALIDATED.equals(id)) 542 { 543 continue; 544 } 545 546 Comment c = new Comment(contentUnversionnedMetadataHolder, id); 547 if (includeNotValidatedComments && !c.isValidated() || includeValidatedComments && c.isValidated()) 548 { 549 comments.add(c); 550 if (isRecursive) 551 { 552 comments.addAll(getComments(c, includeNotValidatedComments, includeValidatedComments, isRecursive)); 553 } 554 } 555 } 556 } 557 558 return comments; 559 } 560 561 @Override 562 public void addReaction(UserIdentity user, ReactionType reactionType) 563 { 564 ReactionableObjectHelper.addReaction(getMetadata(), user, reactionType); 565 } 566 567 @Override 568 public void removeReaction(UserIdentity user, ReactionType reactionType) 569 { 570 ReactionableObjectHelper.removeReaction(getMetadata(), user, reactionType); 571 } 572 573 @Override 574 public List<UserIdentity> getReactionUsers(ReactionType reactionType) 575 { 576 return ReactionableObjectHelper.getReactionUsers(getMetadata(), reactionType); 577 } 578}