From: Klaudio Sinani Date: Mon, 20 Jun 2022 18:13:17 +0000 (+0200) Subject: SONAR-16500 Prevent future dates for project bulk delete action X-Git-Tag: 9.6.0.59041~333 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=2cb3e53879262017a32c3e394ac30669e573c42c;p=sonarqube.git SONAR-16500 Prevent future dates for project bulk delete action --- diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/project/ws/BulkDeleteAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/project/ws/BulkDeleteAction.java index 3a75fb5b14b..fde1db235c1 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/project/ws/BulkDeleteAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/project/ws/BulkDeleteAction.java @@ -20,16 +20,20 @@ package org.sonar.server.project.ws; import com.google.common.base.Strings; +import java.util.Date; import java.util.HashSet; import java.util.List; +import java.util.Optional; import java.util.Set; import javax.annotation.CheckForNull; import javax.annotation.Nullable; +import org.apache.commons.lang.StringUtils; import org.sonar.api.server.ws.Change; import org.sonar.api.server.ws.Request; import org.sonar.api.server.ws.Response; import org.sonar.api.server.ws.WebService; import org.sonar.api.server.ws.WebService.Param; +import org.sonar.api.utils.DateUtils; import org.sonar.core.util.stream.MoreCollectors; import org.sonar.db.DbClient; import org.sonar.db.DbSession; @@ -138,6 +142,7 @@ public class BulkDeleteAction implements ProjectsWsAction { try (DbSession dbSession = dbClient.openSession(false)) { userSession.checkPermission(GlobalPermission.ADMINISTER); checkAtLeastOneParameterIsPresent(searchRequest); + checkIfAnalyzedBeforeIsFutureDate(searchRequest); ComponentQuery query = buildDbQuery(searchRequest); Set componentDtos = new HashSet<>(dbClient.componentDao().selectByQuery(dbSession, query, 0, Integer.MAX_VALUE)); @@ -159,10 +164,22 @@ public class BulkDeleteAction implements ProjectsWsAction { boolean queryPresent = !Strings.isNullOrEmpty(searchRequest.getQuery()); boolean atLeastOneParameterIsPresent = analyzedBeforePresent || projectsPresent || queryPresent; - checkArgument(atLeastOneParameterIsPresent, format("At lease one parameter among %s, %s and %s must be provided", + checkArgument(atLeastOneParameterIsPresent, format("At least one parameter among %s, %s and %s must be provided", PARAM_ANALYZED_BEFORE, PARAM_PROJECTS, Param.TEXT_QUERY)); } + private static void checkIfAnalyzedBeforeIsFutureDate(SearchRequest searchRequest) { + String analyzedBeforeParam = searchRequest.getAnalyzedBefore(); + + Optional.ofNullable(analyzedBeforeParam) + .filter(StringUtils::isNotEmpty) + .map(DateUtils::parseDateOrDateTime) + .ifPresent(analyzedBeforeDate -> { + boolean isFutureDate = new Date().compareTo(analyzedBeforeDate) < 0; + checkArgument(!isFutureDate, format("Provided value for parameter %s must not be a future date", PARAM_ANALYZED_BEFORE)); + }); + } + private static SearchRequest toSearchWsRequest(Request request) { return SearchRequest.builder() .setQualifiers(request.mandatoryParamAsStrings(PARAM_QUALIFIERS)) diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/project/ws/BulkDeleteActionTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/project/ws/BulkDeleteActionTest.java index a4cbce31c8a..a831c480453 100644 --- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/project/ws/BulkDeleteActionTest.java +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/project/ws/BulkDeleteActionTest.java @@ -28,6 +28,8 @@ import java.util.stream.Collectors; import java.util.stream.IntStream; import java.util.stream.Stream; import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang.math.RandomUtils; +import org.joda.time.DateTime; import org.junit.Rule; import org.junit.Test; import org.mockito.ArgumentCaptor; @@ -120,7 +122,7 @@ public class BulkDeleteActionTest { TestRequest request = ws.newRequest(); assertThatThrownBy(request::execute) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("At lease one parameter among analyzedBefore, projects and q must be provided"); + .hasMessage("At least one parameter among analyzedBefore, projects and q must be provided"); } finally { verifyNoDeletions(); verifyNoMoreInteractions(projectLifeCycleListeners); @@ -271,6 +273,25 @@ public class BulkDeleteActionTest { verifyListenersOnProjectsDeleted(toDelete1, toDelete2); } + @Test + public void should_throw_IAE_when_providing_future_date_as_analyzed_before_date() { + userSession.logIn().addPermission(ADMINISTER); + + Date now = new Date(); + Date futureDate = new DateTime(now).plusDays(RandomUtils.nextInt() + 1).toDate(); + ComponentDto project1 = db.components().insertPublicProject(); + db.getDbClient().snapshotDao().insert(db.getSession(), newAnalysis(project1).setCreatedAt(now.getTime())); + ComponentDto project2 = db.components().insertPublicProject(); + db.getDbClient().snapshotDao().insert(db.getSession(), newAnalysis(project2).setCreatedAt(now.getTime())); + db.commit(); + + TestRequest request = ws.newRequest().setParam(PARAM_ANALYZED_BEFORE, formatDate(futureDate)); + + assertThatThrownBy(request::execute) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("Provided value for parameter analyzedBefore must not be a future date"); + } + @Test public void throw_UnauthorizedException_if_not_logged_in() { userSession.anonymous();