diff --git a/domain/src/main/java/org/fao/geonet/repository/userfeedback/UserFeedbackRepository.java b/domain/src/main/java/org/fao/geonet/repository/userfeedback/UserFeedbackRepository.java index 5e4d4a84c6e2..0f2d0c8b4337 100644 --- a/domain/src/main/java/org/fao/geonet/repository/userfeedback/UserFeedbackRepository.java +++ b/domain/src/main/java/org/fao/geonet/repository/userfeedback/UserFeedbackRepository.java @@ -65,6 +65,14 @@ public interface UserFeedbackRepository extends JpaRepository findByMetadata_UuidAndStatusOrderByCreationDateDesc(String metadataUuid, UserRatingStatus status, Pageable p); + /** + * Find child feedback entries for a parent feedback uuid. + * + * @param parentUuid the parent feedback uuid + * @return the list + */ + List findByParent_Uuid(String parentUuid); + /** * Find by metadata uuid order by date desc. * diff --git a/services/src/main/java/org/fao/geonet/api/userfeedback/UserFeedbackAPI.java b/services/src/main/java/org/fao/geonet/api/userfeedback/UserFeedbackAPI.java index b386d57d3ad2..070e45f53691 100644 --- a/services/src/main/java/org/fao/geonet/api/userfeedback/UserFeedbackAPI.java +++ b/services/src/main/java/org/fao/geonet/api/userfeedback/UserFeedbackAPI.java @@ -209,20 +209,14 @@ public RatingAverage getMetadataRating( try { Log.debug("org.fao.geonet.api.userfeedback.UserFeedback", "getMetadataUserComments"); - // Check permission for metadata - final AbstractMetadata metadata = ApiUtils.canViewRecord(metadataUuid, request); - if (metadata == null) { - printOutputMessage(response, HttpStatus.FORBIDDEN, ApiParams.API_RESPONSE_NOT_ALLOWED_CAN_VIEW); - return null; - } - + ApiUtils.canViewRecord(metadataUuid, request); final UserSession session = ApiUtils.getUserSession(httpSession); boolean published = true; // Takes only published comments // showing not published comments only to logged users (maybe better // restrict to Reviewers) - if (session != null && session.isAuthenticated()) { + if (session.isAuthenticated()) { published = false; } @@ -280,7 +274,7 @@ public UserFeedbackDTO getUserComment( // showing not published comments only to logged users (maybe better // restrict to Reviewers) - if (session != null && session.isAuthenticated()) { + if (session.isAuthenticated()) { published = false; } @@ -293,11 +287,7 @@ public UserFeedbackDTO getUserComment( } // Check permission for metadata - final AbstractMetadata metadata = ApiUtils.canViewRecord(userfeedback.getMetadata().getUuid(), request); - if (metadata == null) { - printOutputMessage(response, HttpStatus.FORBIDDEN, ApiParams.API_RESPONSE_NOT_ALLOWED_CAN_VIEW); - return null; - } + ApiUtils.canViewRecord(userfeedback.getMetadata().getUuid(), request); return dto; } @@ -408,13 +398,13 @@ private List getUserFeedback( // showing not published comments only to logged users (maybe better // restrict to Reviewers) - if (session != null && session.isAuthenticated()) { + if (session.isAuthenticated()) { published = false; } List listUserfeedback = null; - if (metadataUuid == null || metadataUuid.equals("")) { + if (metadataUuid == null || metadataUuid.isEmpty()) { listUserfeedback = userFeedbackService.retrieveUserFeedback(size, published); } else { listUserfeedback = userFeedbackService.retrieveUserFeedbackForMetadata(metadataUuid, size, published); @@ -522,7 +512,7 @@ public ResponseEntity newUserFeedback( String catalogueName = settingManager.getValue(SYSTEM_SITE_NAME_PATH); String title = XslUtil.getIndexField(null, userFeedbackDto.getMetadataUUID(), "resourceTitleObject", ""); - if (toAddress.size() > 0) { + if (!toAddress.isEmpty()) { try { Locale[] feedbackLocales = feedbackLanguages.getLocales(locale); @@ -710,22 +700,6 @@ public ResponseEntity sendEmailToContact( return new ResponseEntity<>(HttpStatus.CREATED); } - /** - * Prints the output message. - * - * @param response the response - * @param code the code - * @param message the message - * @throws IOException Signals that an I/O exception has occurred. - */ - private void printOutputMessage(final HttpServletResponse response, final HttpStatus code, final String message) throws IOException { - response.setStatus(code.value()); - final PrintWriter out = response.getWriter(); - response.setContentType("text/html"); - out.println(message); - response.flushBuffer(); - } - /** * Publish. * diff --git a/services/src/main/java/org/fao/geonet/api/userfeedback/UserFeedbackUtils.java b/services/src/main/java/org/fao/geonet/api/userfeedback/UserFeedbackUtils.java index ec5593791ee4..f7560518a8d3 100644 --- a/services/src/main/java/org/fao/geonet/api/userfeedback/UserFeedbackUtils.java +++ b/services/src/main/java/org/fao/geonet/api/userfeedback/UserFeedbackUtils.java @@ -218,7 +218,7 @@ public RatingAverage getAverage(List list) { ISODate maxDate = null; // LAST COMMENT DATE RatingAverage v = null; - if (list.size() > 0) { + if (!list.isEmpty()) { Map ratingAverages = new HashMap<>(); RatingCriteriaRepository criteriaRepository = ApplicationContextHolder.get().getBean(RatingCriteriaRepository.class); List criteriaList = criteriaRepository.findAll(); @@ -231,7 +231,7 @@ public RatingAverage getAverage(List list) { maxDate = new ISODate(userFeedback.getCreationDate().getTime()); } - if (userFeedback.getDetailedRatingList() != null && userFeedback.getDetailedRatingList().size() > 0) { + if (userFeedback.getDetailedRatingList() != null && !userFeedback.getDetailedRatingList().isEmpty()) { for (final Rating rating : userFeedback.getDetailedRatingList()) { Integer criteriaId = rating.getCategory().getId(); @@ -242,9 +242,10 @@ public RatingAverage getAverage(List list) { ratingAverages.get(criteriaId) == null ? value : (ratingAverages.get(criteriaId) + value) / 2); - } - if (criteriaId.equals(AVERAGE_ID)) { - ratingCount++; + + if (criteriaId.equals(AVERAGE_ID)) { + ratingCount++; + } } } @@ -288,6 +289,7 @@ public class RatingAverage { * @param ratingAverages the average for all rating categories * @param userfeedbackCount the userfeedback count * @param lastComment the last comment + * @param ratingCount the rating count */ public RatingAverage(Map ratingAverages, int userfeedbackCount, String lastComment, int ratingCount) { this.ratingAverages = ratingAverages; diff --git a/services/src/main/java/org/fao/geonet/api/userfeedback/service/UserFeedbackDatabaseService.java b/services/src/main/java/org/fao/geonet/api/userfeedback/service/UserFeedbackDatabaseService.java index 62e2cd2c8058..5be37bdcd5d5 100644 --- a/services/src/main/java/org/fao/geonet/api/userfeedback/service/UserFeedbackDatabaseService.java +++ b/services/src/main/java/org/fao/geonet/api/userfeedback/service/UserFeedbackDatabaseService.java @@ -39,6 +39,7 @@ import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import java.util.List; @@ -94,16 +95,17 @@ public void publishUserFeedback(String feedbackUuid, User user) throws ObjectNot * removeUserFeedback(java.lang.String) */ @Override + @Transactional public void removeUserFeedback(String feedbackUuid, String ip) throws Exception { final UserFeedback userFeedback = userFeedbackRepository.findByUuid(feedbackUuid); final Metadata metadata = userFeedback.getMetadata(); - userFeedbackRepository.delete(userFeedback); + deleteUserFeedbackWithChildren(userFeedback); // Then update global metadata rating List listFeedbacks = retrieveUserFeedbackForMetadata(metadata.getUuid(), -1, true); Integer average = 0; - if (listFeedbacks.size() > 0) { + if (!listFeedbacks.isEmpty()) { UserFeedbackUtils.RatingAverage averageRating = new UserFeedbackUtils() .getAverage(listFeedbacks); average = averageRating.getRatingAverages().get(AVERAGE_ID); @@ -111,6 +113,16 @@ public void removeUserFeedback(String feedbackUuid, String ip) throws Exception dataManager.rateMetadata(metadata.getId(), ip, average); } + private void deleteUserFeedbackWithChildren(UserFeedback userFeedback) { + List childFeedbacks = userFeedbackRepository.findByParent_Uuid(userFeedback.getUuid()); + + for (UserFeedback childFeedback : childFeedbacks) { + deleteUserFeedbackWithChildren(childFeedback); + } + + userFeedbackRepository.delete(userFeedback); + } + /* * (non-Javadoc) * diff --git a/services/src/test/java/org/fao/geonet/api/userfeedback/service/UserFeedbackDatabaseServiceTest.java b/services/src/test/java/org/fao/geonet/api/userfeedback/service/UserFeedbackDatabaseServiceTest.java new file mode 100644 index 000000000000..894f5914bafe --- /dev/null +++ b/services/src/test/java/org/fao/geonet/api/userfeedback/service/UserFeedbackDatabaseServiceTest.java @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2001-2026 Food and Agriculture Organization of the + * United Nations (FAO-UN), United Nations World Food Programme (WFP) + * and United Nations Environment Programme (UNEP) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + * + * Contact: Jeroen Ticheler - FAO - Viale delle Terme di Caracalla 2, + * Rome - Italy. email: geonetwork@osgeo.org + */ +package org.fao.geonet.api.userfeedback.service; + +import org.fao.geonet.domain.Metadata; +import org.fao.geonet.domain.userfeedback.UserFeedback; +import org.fao.geonet.domain.userfeedback.UserFeedback.UserRatingStatus; +import org.fao.geonet.kernel.datamanager.IMetadataUtils; +import org.fao.geonet.repository.MetadataRepository; +import org.fao.geonet.repository.UserRepository; +import org.fao.geonet.repository.userfeedback.RatingRepository; +import org.fao.geonet.repository.userfeedback.UserFeedbackRepository; +import org.junit.Before; +import org.junit.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.Collections; + +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.isNull; +import static org.mockito.Mockito.inOrder; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +public class UserFeedbackDatabaseServiceTest { + + @Mock + private IMetadataUtils dataManager; + + @Mock + private MetadataRepository metadataRepository; + + @Mock + private RatingRepository ratingRepository; + + @Mock + private UserFeedbackRepository userFeedbackRepository; + + @Mock + private UserRepository userRepository; + + @InjectMocks + private UserFeedbackDatabaseService service; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + } + + @Test + public void removeUserFeedbackDeletesChildrenBeforeParent() throws Exception { + Metadata metadata = new Metadata(); + metadata.setId(12); + metadata.setUuid("metadata-uuid"); + + UserFeedback parent = new UserFeedback(); + parent.setUuid("parent"); + parent.setMetadata(metadata); + + UserFeedback child = new UserFeedback(); + child.setUuid("child"); + child.setMetadata(metadata); + + UserFeedback grandChild = new UserFeedback(); + grandChild.setUuid("grand-child"); + grandChild.setMetadata(metadata); + + when(userFeedbackRepository.findByUuid("parent")).thenReturn(parent); + when(userFeedbackRepository.findByParent_Uuid("parent")).thenReturn(Collections.singletonList(child)); + when(userFeedbackRepository.findByParent_Uuid("child")).thenReturn(Collections.singletonList(grandChild)); + when(userFeedbackRepository.findByParent_Uuid("grand-child")).thenReturn(Collections.emptyList()); + when(userFeedbackRepository.findByMetadata_UuidAndStatusOrderByCreationDateDesc( + eq("metadata-uuid"), eq(UserRatingStatus.PUBLISHED), isNull())) + .thenReturn(Collections.emptyList()); + + service.removeUserFeedback("parent", "127.0.0.1"); + + org.mockito.InOrder inOrder = inOrder(userFeedbackRepository); + inOrder.verify(userFeedbackRepository).findByUuid("parent"); + inOrder.verify(userFeedbackRepository).findByParent_Uuid("parent"); + inOrder.verify(userFeedbackRepository).findByParent_Uuid("child"); + inOrder.verify(userFeedbackRepository).findByParent_Uuid("grand-child"); + inOrder.verify(userFeedbackRepository).delete(grandChild); + inOrder.verify(userFeedbackRepository).delete(child); + inOrder.verify(userFeedbackRepository).delete(parent); + inOrder.verify(userFeedbackRepository).findByMetadata_UuidAndStatusOrderByCreationDateDesc( + "metadata-uuid", UserRatingStatus.PUBLISHED, null); + + verify(dataManager).rateMetadata(12, "127.0.0.1", 0); + } +}