001/* 002 * (C) Copyright 2018-2020 Nuxeo (http://nuxeo.com/) and others. 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 * Contributors: 017 * Funsho David 018 * Nuno Cunha <ncunha@nuxeo.com> 019 */ 020 021package org.nuxeo.ecm.platform.comment.impl; 022 023import static java.util.Collections.singletonList; 024import static java.util.Collections.singletonMap; 025import static java.util.stream.Collectors.collectingAndThen; 026import static java.util.stream.Collectors.toList; 027import static org.apache.commons.lang3.StringUtils.isBlank; 028import static org.nuxeo.ecm.core.io.marshallers.json.document.DocumentModelJsonReader.applyDirtyPropertyValues; 029import static org.nuxeo.ecm.platform.comment.api.CommentConstants.COMMENT_ANCESTOR_IDS_PROPERTY; 030import static org.nuxeo.ecm.platform.comment.api.CommentConstants.COMMENT_AUTHOR_PROPERTY; 031import static org.nuxeo.ecm.platform.comment.api.CommentConstants.COMMENT_CREATION_DATE_PROPERTY; 032import static org.nuxeo.ecm.platform.comment.api.CommentConstants.COMMENT_PARENT_ID_PROPERTY; 033import static org.nuxeo.ecm.platform.comment.api.CommentConstants.COMMENT_SCHEMA; 034import static org.nuxeo.ecm.platform.comment.api.ExternalEntityConstants.EXTERNAL_ENTITY_FACET; 035import static org.nuxeo.ecm.platform.ec.notification.NotificationConstants.DISABLE_NOTIFICATION_SERVICE; 036import static org.nuxeo.ecm.platform.query.nxql.CoreQueryAndFetchPageProvider.CORE_SESSION_PROPERTY; 037 038import java.io.Serializable; 039import java.time.Instant; 040import java.util.ArrayList; 041import java.util.Collection; 042import java.util.Collections; 043import java.util.List; 044import java.util.Map; 045 046import org.nuxeo.ecm.core.api.CoreInstance; 047import org.nuxeo.ecm.core.api.CoreSession; 048import org.nuxeo.ecm.core.api.DocumentModel; 049import org.nuxeo.ecm.core.api.DocumentRef; 050import org.nuxeo.ecm.core.api.IdRef; 051import org.nuxeo.ecm.core.api.NuxeoPrincipal; 052import org.nuxeo.ecm.core.api.PartialList; 053import org.nuxeo.ecm.core.api.PathRef; 054import org.nuxeo.ecm.core.api.SortInfo; 055import org.nuxeo.ecm.core.api.security.SecurityConstants; 056import org.nuxeo.ecm.platform.comment.api.Comment; 057import org.nuxeo.ecm.platform.comment.api.CommentEvents; 058import org.nuxeo.ecm.platform.comment.api.exceptions.CommentNotFoundException; 059import org.nuxeo.ecm.platform.comment.api.exceptions.CommentSecurityException; 060import org.nuxeo.ecm.platform.query.api.PageProvider; 061import org.nuxeo.ecm.platform.query.api.PageProviderService; 062import org.nuxeo.runtime.api.Framework; 063 064/** 065 * Comment service implementation. The comments are linked together thanks to a parent document id property. 066 * 067 * @since 10.3 068 * @deprecated since 11.1, use {@link TreeCommentManager} instead 069 */ 070@Deprecated(since = "11.1") 071public class PropertyCommentManager extends AbstractCommentManager { 072 073 /** @deprecated since 11.1, use {@link #GET_EXTERNAL_COMMENT_PAGEPROVIDER_NAME} instead */ 074 @Deprecated(since = "11.1") 075 protected static final String GET_COMMENT_PAGEPROVIDER_NAME = "GET_COMMENT_AS_EXTERNAL_ENTITY"; 076 077 /** @since 11.1 */ 078 protected static final String GET_EXTERNAL_COMMENT_PAGEPROVIDER_NAME = "GET_EXTERNAL_COMMENT_BY_COMMENT_ANCESTOR"; 079 080 protected static final String GET_COMMENTS_FOR_DOC_PAGEPROVIDER_NAME = "GET_COMMENTS_FOR_DOCUMENT"; 081 082 protected static final String GET_COMMENTS_FOR_DOCS_PAGEPROVIDER_NAME = "GET_COMMENTS_FOR_DOCUMENTS_BY_COMMENT_ANCESTOR"; 083 084 protected static final String HIDDEN_FOLDER_TYPE = "HiddenFolder"; 085 086 protected static final String COMMENT_NAME = "comment"; 087 088 @Override 089 @SuppressWarnings("unchecked") 090 public List<DocumentModel> getComments(CoreSession session, DocumentModel docModel) 091 throws CommentSecurityException { 092 093 DocumentRef docRef = getAncestorRef(session, docModel); 094 095 if (session.exists(docRef) && !session.hasPermission(docRef, SecurityConstants.READ)) { 096 throw new CommentSecurityException("The user " + session.getPrincipal().getName() 097 + " does not have access to the comments of document " + docModel.getId()); 098 } 099 PageProviderService ppService = Framework.getService(PageProviderService.class); 100 return CoreInstance.doPrivileged(session, s -> { 101 Map<String, Serializable> props = Collections.singletonMap(CORE_SESSION_PROPERTY, (Serializable) s); 102 PageProvider<DocumentModel> pageProvider = (PageProvider<DocumentModel>) ppService.getPageProvider( 103 GET_COMMENTS_FOR_DOC_PAGEPROVIDER_NAME, 104 singletonList(new SortInfo(COMMENT_CREATION_DATE_PROPERTY, true)), null, null, props, 105 docModel.getId()); 106 return pageProvider.getCurrentPage(); 107 }); 108 } 109 110 @Override 111 public List<DocumentModel> getComments(DocumentModel docModel, DocumentModel parent) { 112 throw new UnsupportedOperationException("This service implementation does not implement deprecated API."); 113 } 114 115 @Override 116 public DocumentModel createComment(DocumentModel docModel, String comment) { 117 throw new UnsupportedOperationException("This service implementation does not implement deprecated API."); 118 } 119 120 @Override 121 @SuppressWarnings("removal") 122 public DocumentModel createComment(DocumentModel docModel, String text, String author) { 123 throw new UnsupportedOperationException("This service implementation does not implement deprecated API."); 124 } 125 126 @Override 127 public DocumentModel createComment(DocumentModel docModel, DocumentModel commentModel) 128 throws CommentSecurityException { 129 130 NuxeoPrincipal principal = commentModel.getPrincipal(); 131 // Open a session as system user since the parent document model can be a comment 132 CoreSession session = CoreInstance.getCoreSessionSystem(docModel.getRepositoryName()); 133 DocumentRef docRef = getTopLevelDocumentRef(session, docModel.getRef()); 134 if (!session.hasPermission(principal, docRef, SecurityConstants.READ)) { 135 throw new CommentSecurityException( 136 "The user " + principal.getName() + " can not create comments on document " + docModel.getId()); 137 } 138 139 String path = getCommentContainerPath(session, docModel.getId()); 140 141 DocumentModel commentModelToCreate = session.createDocumentModel(path, COMMENT_NAME, commentModel.getType()); 142 commentModelToCreate.copyContent(commentModel); 143 commentModelToCreate.setPropertyValue(COMMENT_PARENT_ID_PROPERTY, docModel.getId()); 144 commentModelToCreate.setPropertyValue(COMMENT_ANCESTOR_IDS_PROPERTY, 145 computeAncestorIds(session, docModel.getId())); 146 DocumentModel comment = session.createDocument(commentModelToCreate); 147 comment.detach(true); 148 notifyEvent(session, CommentEvents.COMMENT_ADDED, docModel, comment); 149 150 return comment; 151 } 152 153 @Override 154 @SuppressWarnings("removal") 155 public DocumentModel createComment(DocumentModel docModel, DocumentModel parent, DocumentModel child) { 156 throw new UnsupportedOperationException("This service implementation does not implement deprecated API."); 157 } 158 159 @Override 160 @SuppressWarnings("removal") 161 public void deleteComment(DocumentModel docModel, DocumentModel comment) { 162 throw new UnsupportedOperationException("This service implementation does not implement deprecated API."); 163 } 164 165 @Override 166 @SuppressWarnings("removal") 167 public List<DocumentModel> getDocumentsForComment(DocumentModel comment) { 168 throw new UnsupportedOperationException("This service implementation does not implement deprecated API."); 169 } 170 171 @Override 172 public DocumentModel getThreadForComment(DocumentModel comment) throws CommentSecurityException { 173 return getThreadForComment(comment.getCoreSession(), comment); 174 } 175 176 @Override 177 public DocumentModel createLocatedComment(DocumentModel docModel, DocumentModel comment, String path) { 178 CoreSession session = docModel.getCoreSession(); 179 DocumentRef docRef = getTopLevelDocumentRef(session, docModel.getRef()); 180 if (!session.hasPermission(docRef, SecurityConstants.READ)) { 181 throw new CommentSecurityException("The user " + session.getPrincipal().getName() 182 + " can not create comments on document " + docModel.getId()); 183 } 184 return CoreInstance.doPrivileged(session, s -> { 185 DocumentModel commentModel = s.createDocumentModel(path, COMMENT_NAME, comment.getType()); 186 commentModel.copyContent(comment); 187 commentModel.setPropertyValue(COMMENT_PARENT_ID_PROPERTY, docModel.getId()); 188 commentModel.setPropertyValue(COMMENT_ANCESTOR_IDS_PROPERTY, computeAncestorIds(s, docModel.getId())); 189 commentModel = s.createDocument(commentModel); 190 notifyEvent(session, CommentEvents.COMMENT_ADDED, docModel, commentModel); 191 return commentModel; 192 }); 193 } 194 195 @Override 196 public Comment createComment(CoreSession session, Comment comment) 197 throws CommentNotFoundException, CommentSecurityException { 198 String parentId = comment.getParentId(); 199 DocumentRef parentRef = new IdRef(parentId); 200 // Parent document can be a comment, check existence as a privileged user 201 if (!CoreInstance.doPrivileged(session, s -> { 202 return s.exists(parentRef); 203 })) { 204 throw new CommentNotFoundException("The document or comment " + comment.getParentId() + " does not exist."); 205 } 206 DocumentRef ancestorRef = CoreInstance.doPrivileged(session, s -> { 207 DocumentModel parentDocModel = s.getDocument(parentRef); 208 if (parentDocModel.hasSchema(COMMENT_SCHEMA)) { 209 return getAncestorRef(s, parentDocModel); 210 } 211 return parentDocModel.getRef(); 212 }); 213 if (!session.hasPermission(ancestorRef, SecurityConstants.READ)) { 214 throw new CommentSecurityException("The user " + session.getPrincipal().getName() 215 + " can not create comments on document " + parentId); 216 } 217 218 fillCommentForCreation(session, comment); 219 220 return CoreInstance.doPrivileged(session, s -> { 221 String path = getCommentContainerPath(s, parentId); 222 DocumentModel commentModel = session.createDocumentModel(path, COMMENT_NAME, 223 comment.getDocument().getType()); 224 if (comment.getDocument().hasFacet(EXTERNAL_ENTITY_FACET)) { 225 commentModel.addFacet(EXTERNAL_ENTITY_FACET); 226 } 227 applyDirtyPropertyValues(comment.getDocument(), commentModel); 228 229 // Compute the list of ancestor ids 230 commentModel.setPropertyValue(COMMENT_ANCESTOR_IDS_PROPERTY, computeAncestorIds(s, parentId)); 231 commentModel = s.createDocument(commentModel); 232 notifyEvent(s, CommentEvents.COMMENT_ADDED, commentModel); 233 return commentModel.getAdapter(Comment.class); 234 }); 235 } 236 237 @Override 238 public Comment getComment(CoreSession session, String commentId) 239 throws CommentNotFoundException, CommentSecurityException { 240 DocumentRef commentRef = new IdRef(commentId); 241 // Parent document can be a comment, check existence as a privileged user 242 if (!CoreInstance.doPrivileged(session, s -> { 243 return s.exists(commentRef); 244 })) { 245 throw new CommentNotFoundException("The comment " + commentId + " does not exist."); 246 } 247 NuxeoPrincipal principal = session.getPrincipal(); 248 return CoreInstance.doPrivileged(session, s -> { 249 DocumentModel commentModel = s.getDocument(commentRef); 250 DocumentRef documentRef = getTopLevelDocumentRef(s, commentModel.getRef()); 251 if (!s.hasPermission(principal, documentRef, SecurityConstants.READ)) { 252 throw new CommentSecurityException("The user " + principal.getName() 253 + " does not have access to the comments of document " + documentRef.reference()); 254 } 255 256 return commentModel.getAdapter(Comment.class); 257 }); 258 } 259 260 @Override 261 @SuppressWarnings("unchecked") 262 public PartialList<Comment> getComments(CoreSession session, String documentId, Long pageSize, 263 Long currentPageIndex, boolean sortAscending) throws CommentSecurityException { 264 DocumentRef docRef = new IdRef(documentId); 265 PageProviderService ppService = Framework.getService(PageProviderService.class); 266 NuxeoPrincipal principal = session.getPrincipal(); 267 return CoreInstance.doPrivileged(session, s -> { 268 if (s.exists(docRef)) { 269 DocumentRef ancestorRef = getTopLevelDocumentRef(s, docRef); 270 if (s.exists(ancestorRef) && !s.hasPermission(principal, ancestorRef, SecurityConstants.READ)) { 271 throw new CommentSecurityException("The user " + principal.getName() 272 + " does not have access to the comments of document " + documentId); 273 } 274 } 275 Map<String, Serializable> props = Collections.singletonMap(CORE_SESSION_PROPERTY, (Serializable) s); 276 PageProvider<DocumentModel> pageProvider = (PageProvider<DocumentModel>) ppService.getPageProvider( 277 GET_COMMENTS_FOR_DOC_PAGEPROVIDER_NAME, 278 singletonList(new SortInfo(COMMENT_CREATION_DATE_PROPERTY, sortAscending)), pageSize, 279 currentPageIndex, props, documentId); 280 List<DocumentModel> commentList = pageProvider.getCurrentPage(); 281 return commentList.stream() 282 .map(doc -> doc.getAdapter(Comment.class)) 283 .collect(collectingAndThen(toList(), 284 list -> new PartialList<>(list, pageProvider.getResultsCount()))); 285 }); 286 } 287 288 @Override 289 public List<Comment> getComments(CoreSession session, Collection<String> documentIds) { 290 PageProviderService ppService = Framework.getService(PageProviderService.class); 291 292 Map<String, Serializable> props = Map.of(CORE_SESSION_PROPERTY, (Serializable) session); 293 @SuppressWarnings("unchecked") 294 var pageProvider = (PageProvider<DocumentModel>) ppService.getPageProvider( 295 GET_COMMENTS_FOR_DOCS_PAGEPROVIDER_NAME, null, null, null, props, new ArrayList<>(documentIds)); 296 return pageProvider.getCurrentPage().stream().map(doc -> doc.getAdapter(Comment.class)).collect(toList()); 297 } 298 299 @Override 300 public Comment updateComment(CoreSession session, String commentId, Comment comment) 301 throws CommentNotFoundException { 302 IdRef commentRef = new IdRef(commentId); 303 NuxeoPrincipal principal = session.getPrincipal(); 304 return CoreInstance.doPrivileged(session, s -> { 305 if (!s.exists(commentRef)) { 306 throw new CommentNotFoundException("The comment " + commentId + " does not exist."); 307 } 308 DocumentModel commentModel = s.getDocument(commentRef); 309 if (!principal.isAdministrator() 310 && !principal.getName().equals(commentModel.getPropertyValue(COMMENT_AUTHOR_PROPERTY))) { 311 throw new CommentSecurityException( 312 "The user " + principal.getName() + " cannot edit comment " + commentId); 313 } 314 315 // Initiate Modification Date if it is not done yet 316 if (comment.getModificationDate() == null) { 317 comment.setModificationDate(Instant.now()); 318 } 319 if (comment.getDocument().hasFacet(EXTERNAL_ENTITY_FACET)) { 320 commentModel.addFacet(EXTERNAL_ENTITY_FACET); 321 } 322 applyDirtyPropertyValues(comment.getDocument(), commentModel); 323 s.saveDocument(commentModel); 324 notifyEvent(s, CommentEvents.COMMENT_UPDATED, commentModel); 325 return commentModel.getAdapter(Comment.class); 326 }); 327 } 328 329 @Override 330 public void deleteComment(CoreSession session, String commentId) 331 throws CommentNotFoundException, CommentSecurityException { 332 IdRef commentRef = new IdRef(commentId); 333 // Document can be a comment, check existence as a privileged user 334 if (!CoreInstance.doPrivileged(session, s -> { 335 return s.exists(commentRef); 336 })) { 337 throw new CommentNotFoundException("The comment " + commentId + " does not exist."); 338 } 339 340 NuxeoPrincipal principal = session.getPrincipal(); 341 CoreInstance.doPrivileged(session, s -> { 342 DocumentModel comment = s.getDocument(commentRef); 343 String parentId = (String) comment.getPropertyValue(COMMENT_PARENT_ID_PROPERTY); 344 DocumentRef ancestorRef = getTopLevelDocumentRef(s, commentRef); 345 if (s.exists(ancestorRef) && !principal.isAdministrator() 346 && !comment.getPropertyValue(COMMENT_AUTHOR_PROPERTY).equals(principal.getName()) 347 && !s.hasPermission(principal, ancestorRef, SecurityConstants.EVERYTHING)) { 348 throw new CommentSecurityException( 349 "The user " + principal.getName() + " cannot delete comments of the document " + parentId); 350 } 351 // Allows the access to its data if needed in listeners 352 comment.detach(true); 353 s.removeDocument(commentRef); 354 notifyEvent(s, CommentEvents.COMMENT_REMOVED, comment); 355 }); 356 } 357 358 @Override 359 public Comment getExternalComment(CoreSession session, String documentId, String entityId) 360 throws CommentNotFoundException { 361 DocumentModel commentModel = getExternalCommentModel(session, documentId, entityId); 362 if (commentModel == null) { 363 throw new CommentNotFoundException("The external comment " + entityId + " does not exist."); 364 } 365 String parentId = (String) commentModel.getPropertyValue(COMMENT_PARENT_ID_PROPERTY); 366 if (!session.hasPermission(getTopLevelDocumentRef(session, commentModel.getRef()), SecurityConstants.READ)) { 367 throw new CommentSecurityException("The user " + session.getPrincipal().getName() 368 + " does not have access to the comments of document " + parentId); 369 } 370 return commentModel.getAdapter(Comment.class); 371 } 372 373 @Override 374 public Comment updateExternalComment(CoreSession session, String documentId, String entityId, Comment comment) 375 throws CommentNotFoundException { 376 DocumentModel commentModel = getExternalCommentModel(session, documentId, entityId); 377 if (commentModel == null) { 378 throw new CommentNotFoundException("The external comment " + entityId + " does not exist."); 379 } 380 NuxeoPrincipal principal = session.getPrincipal(); 381 if (!principal.isAdministrator() 382 && !principal.getName().equals(commentModel.getPropertyValue(COMMENT_AUTHOR_PROPERTY))) { 383 throw new CommentSecurityException( 384 "The user " + principal.getName() + " can not edit comments of document " + comment.getParentId()); 385 } 386 return CoreInstance.doPrivileged(session, s -> { 387 // Initiate Modification Date if it is not done yet 388 if (comment.getModificationDate() == null) { 389 comment.setModificationDate(Instant.now()); 390 } 391 applyDirtyPropertyValues(comment.getDocument(), commentModel); 392 s.saveDocument(commentModel); 393 notifyEvent(s, CommentEvents.COMMENT_UPDATED, commentModel); 394 return commentModel.getAdapter(Comment.class); 395 }); 396 } 397 398 @Override 399 public void deleteExternalComment(CoreSession session, String documentId, String entityId) 400 throws CommentNotFoundException { 401 DocumentModel commentModel = getExternalCommentModel(session, documentId, entityId); 402 if (commentModel == null) { 403 throw new CommentNotFoundException("The external comment " + entityId + " does not exist."); 404 } 405 NuxeoPrincipal principal = session.getPrincipal(); 406 String parentId = (String) commentModel.getPropertyValue(COMMENT_PARENT_ID_PROPERTY); 407 if (!principal.isAdministrator() 408 && !commentModel.getPropertyValue(COMMENT_AUTHOR_PROPERTY).equals(principal.getName()) 409 && !session.hasPermission(principal, getTopLevelDocumentRef(session, commentModel.getRef()), 410 SecurityConstants.EVERYTHING)) { 411 throw new CommentSecurityException( 412 "The user " + principal.getName() + " can not delete comments of document " + parentId); 413 } 414 CoreInstance.doPrivileged(session, s -> { 415 DocumentModel comment = s.getDocument(commentModel.getRef()); 416 comment.detach(true); 417 s.removeDocument(commentModel.getRef()); 418 notifyEvent(s, CommentEvents.COMMENT_REMOVED, comment); 419 }); 420 } 421 422 @Override 423 public boolean hasFeature(Feature feature) { 424 switch (feature) { 425 case COMMENTS_LINKED_WITH_PROPERTY: 426 return true; 427 case COMMENTS_ARE_SPECIAL_CHILDREN: 428 return false; 429 default: 430 throw new UnsupportedOperationException(feature.name()); 431 } 432 } 433 434 @Override 435 protected DocumentModel getTopLevelDocument(CoreSession s, DocumentModel commentDoc) { 436 DocumentRef ancestorRef = getAncestorRef(s, commentDoc); 437 return s.getDocument(ancestorRef); 438 } 439 440 @SuppressWarnings("unchecked") 441 protected DocumentModel getExternalCommentModel(CoreSession session, String documentId, String entityId) { 442 return CoreInstance.doPrivileged(session, s -> { 443 PageProviderService ppService = Framework.getService(PageProviderService.class); 444 Map<String, Serializable> props = singletonMap(CORE_SESSION_PROPERTY, (Serializable) s); 445 PageProvider<DocumentModel> pageProvider; 446 // backward compatibility 447 if (isBlank(documentId)) { 448 pageProvider = (PageProvider<DocumentModel>) ppService.getPageProvider(GET_COMMENT_PAGEPROVIDER_NAME, null, 449 1L, 0L, props, entityId); 450 } else { 451 pageProvider = (PageProvider<DocumentModel>) ppService.getPageProvider( 452 GET_EXTERNAL_COMMENT_PAGEPROVIDER_NAME, null, 1L, 0L, props, documentId, entityId); 453 } 454 List<DocumentModel> results = pageProvider.getCurrentPage(); 455 if (results.isEmpty()) { 456 return null; 457 } 458 return results.get(0); 459 }); 460 } 461 462 protected String getCommentContainerPath(CoreSession session, String commentedDocumentId) { 463 return CoreInstance.doPrivileged(session, s -> { 464 // Create or retrieve the folder to store the comment. 465 // If the document is under a domain, the folder is a child of this domain. 466 // Otherwise, it is a child of the root document. 467 DocumentModel annotatedDoc = s.getDocument(new IdRef(commentedDocumentId)); 468 String parentPath = "/"; 469 if (annotatedDoc.getPath().segmentCount() > 1) { 470 parentPath += annotatedDoc.getPath().segment(0); 471 } 472 PathRef ref = new PathRef(parentPath, COMMENTS_DIRECTORY); 473 DocumentModel commentFolderDoc = s.createDocumentModel(parentPath, COMMENTS_DIRECTORY, HIDDEN_FOLDER_TYPE); 474 // No need to notify the creation of the Comments folder 475 commentFolderDoc.putContextData(DISABLE_NOTIFICATION_SERVICE, true); 476 s.getOrCreateDocument(commentFolderDoc); 477 s.save(); 478 return ref.toString(); 479 }); 480 } 481 482 // former top level document method 483 protected DocumentRef getAncestorRef(CoreSession session, DocumentModel documentModel) { 484 if (!documentModel.hasSchema(COMMENT_SCHEMA)) { 485 return documentModel.getRef(); 486 } 487 // thread is the higher comment in a succession of replies 488 DocumentModel thread = getThreadForComment(session, documentModel); 489 return new IdRef((String) thread.getPropertyValue(COMMENT_PARENT_ID_PROPERTY)); 490 } 491 492 protected DocumentModel getThreadForComment(CoreSession s, DocumentModel comment) throws CommentSecurityException { 493 NuxeoPrincipal principal = s.getPrincipal(); 494 return CoreInstance.doPrivileged(s, session -> { 495 DocumentModel thread = comment; 496 DocumentModel parent = s.getDocument( 497 new IdRef((String) thread.getPropertyValue(COMMENT_PARENT_ID_PROPERTY))); 498 if (parent.hasSchema(COMMENT_SCHEMA)) { 499 thread = getThreadForComment(parent); 500 } 501 DocumentRef ancestorRef = s.getDocument( 502 new IdRef((String) thread.getPropertyValue(COMMENT_PARENT_ID_PROPERTY))).getRef(); 503 if (!s.hasPermission(principal, ancestorRef, SecurityConstants.READ)) { 504 throw new CommentSecurityException("The user " + principal.getName() 505 + " does not have access to the comments of document " + ancestorRef.reference()); 506 } 507 return thread; 508 }); 509 } 510 511 @Override 512 protected DocumentModel getCommentedDocument(CoreSession session, DocumentModel commentDoc) { 513 String parentId = (String) commentDoc.getPropertyValue(COMMENT_PARENT_ID_PROPERTY); 514 return session.getDocument(new IdRef(parentId)); 515 } 516}