001/* 002 * Copyright 2024 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.cms.repository.comment; 017 018import java.time.ZonedDateTime; 019import java.util.List; 020import java.util.Optional; 021import java.util.function.BiFunction; 022 023import org.apache.commons.lang3.StringUtils; 024 025import org.ametys.cms.data.RichText; 026import org.ametys.cms.repository.CommentableAmetysObject; 027import org.ametys.plugins.repository.AmetysRepositoryException; 028import org.ametys.plugins.repository.data.holder.ModifiableDataHolder; 029 030/** 031 * A comment on a {@link CommentableAmetysObject} with rich text content 032 */ 033public class RichTextComment extends AbstractComment 034{ 035 036 /** Constants for the content Metadata */ 037 public static final String METADATA_RICHTEXT_COMMENT_CONTENT = "richtextcontent"; 038 039 /** Attribute Description for editing */ 040 public static final String ATTRIBUTE_CONTENT_FOR_EDITING = "contentEditing"; 041 /** Attribute Description for editing */ 042 public static final String ATTRIBUTE_CONTENT_FOR_RENDERING = "contentRendering"; 043 /** Attribute Description abstract */ 044 public static final String ATTRIBUTE_CONTENT_ABSTRACT = "contentAbstract"; 045 046 /** 047 * Retrieves a comment by its id 048 * @param contentUnversionedDataHolder The unversioned data holder of the content hosting the comment 049 * @param commentId The id of the comment to retrieve 050 * @throws AmetysRepositoryException if an error occurred 051 */ 052 public RichTextComment(ModifiableDataHolder contentUnversionedDataHolder, String commentId) 053 { 054 super(contentUnversionedDataHolder, commentId); 055 } 056 057 /** 058 * Creates a new comment on the content 059 * @param contentUnversionedDataHolder The unversioned data holder of the content where to add the new comment 060 */ 061 public RichTextComment(ModifiableDataHolder contentUnversionedDataHolder) 062 { 063 this(contentUnversionedDataHolder, Optional.empty(), Optional.empty()); 064 } 065 066 /** 067 * Creates a new comment on the content, with the given id and creation date 068 * This method allow to create a comment from existing data (ex: data import from archive) 069 * The id is not generated here, the source is trusted. Be careful using this method 070 * @param contentUnversionedDataHolder The unversioned data holder of the content where to add the new comment 071 * @param commentId the comment's id 072 * @param creationDate the comment's creation date 073 */ 074 public RichTextComment(ModifiableDataHolder contentUnversionedDataHolder, String commentId, ZonedDateTime creationDate) 075 { 076 this(contentUnversionedDataHolder, Optional.ofNullable(commentId), Optional.ofNullable(creationDate)); 077 } 078 079 private RichTextComment(ModifiableDataHolder contentUnversionedDataHolder, Optional<String> commentId, Optional<ZonedDateTime> creationDate) 080 { 081 super(contentUnversionedDataHolder, commentId, creationDate); 082 } 083 084 /** 085 * Creates a new sub comment of the comment 086 * @param comment The parent comment 087 */ 088 public RichTextComment(RichTextComment comment) 089 { 090 this(comment, Optional.empty(), Optional.empty()); 091 } 092 093 /** 094 * Creates a new sub comment of the comment, with the given id and creation date 095 * This method allow to create a sub comment from existing data (ex: data import from archive) 096 * The id is not generated here, the source is trusted. Be careful using this method 097 * @param comment The parent comment 098 * @param commentId the sub comment's id 099 * @param creationDate the sub comment's creation date 100 */ 101 public RichTextComment(RichTextComment comment, String commentId, ZonedDateTime creationDate) 102 { 103 this(comment, Optional.ofNullable(commentId), Optional.ofNullable(creationDate)); 104 } 105 106 private RichTextComment(RichTextComment comment, Optional<String> commentId, Optional<ZonedDateTime> creationDate) 107 { 108 super(comment, commentId, creationDate); 109 } 110 111 /** 112 * Creates a reference comment of the comment, with the given comment 113 * @param parentComment The parent comment 114 * @param refComment the referenced comment 115 */ 116 public RichTextComment(RichTextComment parentComment, AbstractComment refComment) 117 { 118 super(parentComment, refComment); 119 } 120 121 /** 122 * Get a comment 123 * @param contentUnversionedDataHolder the content data holder 124 * @param commentId The comment identifier 125 * @return The comment 126 * @throws AmetysRepositoryException if the comment does not exist 127 */ 128 public static RichTextComment getComment(ModifiableDataHolder contentUnversionedDataHolder, String commentId) throws AmetysRepositoryException 129 { 130 return new RichTextComment(contentUnversionedDataHolder, commentId); 131 } 132 133 /** 134 * Get the comments of a content 135 * @param <T> type of the value to retrieve 136 * @param parentComment The parent comment 137 * @param includeNotValidatedComments True to include the comments that are not validated 138 * @param includeValidatedComments True to include the comments that are validated 139 * @return the list of comments 140 * @throws AmetysRepositoryException If an error occurred 141 */ 142 public static <T extends AbstractComment> List<T> getComments(RichTextComment parentComment, boolean includeNotValidatedComments, boolean includeValidatedComments) throws AmetysRepositoryException 143 { 144 return getComments(parentComment, includeNotValidatedComments, includeValidatedComments, false); 145 } 146 147 /** 148 * Get the comments of a content 149 * @param <T> type of the value to retrieve 150 * @param parentComment The parent comment 151 * @param includeNotValidatedComments True to include the comments that are not validated 152 * @param includeValidatedComments True to include the comments that are validated 153 * @param withSubComment true if we want to get all child comments 154 * @return the list of comments 155 * @throws AmetysRepositoryException If an error occurred 156 */ 157 @SuppressWarnings("unchecked") 158 public static <T extends AbstractComment> List<T> getComments(RichTextComment parentComment, boolean includeNotValidatedComments, boolean includeValidatedComments, boolean withSubComment) throws AmetysRepositoryException 159 { 160 return (List<T>) getComments(parentComment, includeNotValidatedComments, includeValidatedComments, withSubComment, getCreationFunction()); 161 } 162 163 /** 164 * Get the comments of a content 165 * @param <T> type of the value to retrieve 166 * @param contentUnversionedDataHolder The content unversioned data holder 167 * @param includeNotValidatedComments True to include the comments that are not validated 168 * @param includeValidatedComments True to include the comments that are validated 169 * @return the list of comments 170 * @throws AmetysRepositoryException If an error occurred 171 */ 172 public static <T extends AbstractComment> List<T> getComments(ModifiableDataHolder contentUnversionedDataHolder, boolean includeNotValidatedComments, boolean includeValidatedComments) throws AmetysRepositoryException 173 { 174 return getComments(contentUnversionedDataHolder, includeNotValidatedComments, includeValidatedComments, false); 175 } 176 177 /** 178 * Get the comments of a content 179 * @param <T> type of the value to retrieve 180 * @param contentUnversionedDataHolder The content unversioned metadata holder 181 * @param includeNotValidatedComments True to include the comments that are not validated 182 * @param includeValidatedComments True to include the comments that are validated 183 * @param isRecursive true if we want to have sub comments 184 * @return the list of comments 185 * @throws AmetysRepositoryException If an error occurred 186 */ 187 public static <T extends AbstractComment> List<T> getComments(ModifiableDataHolder contentUnversionedDataHolder, boolean includeNotValidatedComments, boolean includeValidatedComments, boolean isRecursive) throws AmetysRepositoryException 188 { 189 return getComments(contentUnversionedDataHolder, includeNotValidatedComments, includeValidatedComments, isRecursive, getCreationFunction()); 190 } 191 192 @Override 193 protected void update() 194 { 195 long validated = 0; 196 long notValidated = 0; 197 198 ModifiableDataHolder dataHolder = _rootDataHolder; 199 if (isSubComment()) 200 { 201 dataHolder = getCommentParent()._rootDataHolder; 202 } 203 204 List<RichTextComment> comments = getComments(dataHolder, true, true, false, getCreationFunction()); 205 206 for (AbstractComment comment : comments) 207 { 208 if (comment.isValidated()) 209 { 210 validated++; 211 } 212 else 213 { 214 notValidated++; 215 } 216 } 217 218 dataHolder.setValue(METADATA_COMMENTS_VALIDATED, validated); 219 dataHolder.setValue(METADATA_COMMENTS_NOTVALIDATED, notValidated); 220 } 221 222 @SuppressWarnings("unchecked") 223 @Override 224 public RichTextComment getCommentParent() 225 { 226 if (isSubComment()) 227 { 228 String parentId = StringUtils.substringBeforeLast(this.getId(), ID_SEPARATOR); 229 return new RichTextComment(_rootDataHolder, parentId); 230 } 231 return null; 232 } 233 234 @SuppressWarnings("unchecked") 235 @Override 236 public List<RichTextComment> getSubComment(boolean includeNotValidatedComments, boolean includeValidatedComments) 237 { 238 return getComments(this, includeNotValidatedComments, includeValidatedComments); 239 } 240 241 @SuppressWarnings("unchecked") 242 @Override 243 public RichTextComment getReferencedComment() 244 { 245 return getReferencedComment(this, getCreationFunction()); 246 } 247 248 /** 249 * Create sub comment from this comment 250 * @return the sub comment 251 */ 252 @SuppressWarnings("unchecked") 253 @Override 254 public <T extends AbstractComment> T createSubComment() 255 { 256 return (T) new RichTextComment(this); 257 } 258 259 @SuppressWarnings("unchecked") 260 @Override 261 public <T extends AbstractComment> T createSubComment(String commentId, ZonedDateTime creationDate) 262 { 263 return (T) new RichTextComment(this, commentId, creationDate); 264 } 265 266 @SuppressWarnings("unchecked") 267 @Override 268 public RichTextComment createReferencedComment(AbstractComment comment) 269 { 270 return new RichTextComment(this, comment); 271 } 272 273 @SuppressWarnings("unchecked") 274 private static <T extends AbstractComment> BiFunction<ModifiableDataHolder, String, T> getCreationFunction() 275 { 276 return (dataHolder, name) -> { 277 RichTextComment comment = new RichTextComment(dataHolder, name); 278 return (T) comment; 279 }; 280 } 281 282 /** 283 * Set rich text comment 284 * @param richText the content of the comment 285 */ 286 public void setRichTextContent(RichText richText) 287 { 288 _commentComposite.setValue(METADATA_RICHTEXT_COMMENT_CONTENT, richText, org.ametys.cms.data.type.ModelItemTypeConstants.RICH_TEXT_ELEMENT_TYPE_ID); 289 } 290 291 /** 292 * Get the rich text content 293 * @return rich text content 294 */ 295 public RichText getRichTextContent() 296 { 297 return _commentComposite.getValueOfType(METADATA_RICHTEXT_COMMENT_CONTENT, org.ametys.cms.data.type.ModelItemTypeConstants.RICH_TEXT_ELEMENT_TYPE_ID); 298 } 299 300 /** 301 * Check if there is a rich text content 302 * @return true if there is a rich text content 303 */ 304 public boolean hasRichTextContent() 305 { 306 return _commentComposite.hasValue(METADATA_RICHTEXT_COMMENT_CONTENT); 307 } 308 309}