Skip to content

Commit

Permalink
[backend] feat: added new bulk update, delete and test functions for …
Browse files Browse the repository at this point in the history
…injects

[backend] deprecate: marked existing bulk functions as deprecated
[frontend] feat: plugged the new bulk function in the injects tables for scenarios and simulations
[frontend] feat: select all now select all elements from all the pages in data tables
[frontend] feat: select all + any filter or text search set means that only the filterred element will count as selected
  • Loading branch information
impolitepanda committed Jan 9, 2025
1 parent ad0ec3b commit 3ace5a8
Show file tree
Hide file tree
Showing 35 changed files with 1,540 additions and 493 deletions.
2 changes: 1 addition & 1 deletion .drone.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ steps:
MINIO_ENDPOINT: minio
MINIO_PORT: 9000
commands:
- mvn clean install -q -DskipTests
- mvn clean install -DskipTests
- mvn spotless:check
- cd openbas-api
- mvn test -q
Expand Down
5 changes: 5 additions & 0 deletions openbas-api/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,11 @@
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
Expand Down Expand Up @@ -81,13 +80,6 @@ public Iterable<InjectOutput> exerciseInjectsSimple(
joinMap);
}

@DeleteMapping(EXERCISE_URI + "/{exerciseId}/injects")
@PreAuthorize("isExercisePlanner(#exerciseId)")
public void deleteListOfInjectsForExercise(
@PathVariable final String exerciseId, @RequestBody List<String> injectIds) {
injectService.deleteAllByIds(injectIds);
}

@PostMapping("/api/exercise/{exerciseId}/injects/test")
public Page<InjectTestStatus> findAllExerciseInjectTests(
@PathVariable @NotBlank String exerciseId,
Expand Down
80 changes: 58 additions & 22 deletions openbas-api/src/main/java/io/openbas/rest/inject/InjectApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import io.openbas.executors.Executor;
import io.openbas.injector_contract.ContractType;
import io.openbas.rest.atomic_testing.form.InjectResultOutput;
import io.openbas.rest.exception.BadRequestException;
import io.openbas.rest.exception.ElementNotFoundException;
import io.openbas.rest.helper.RestBehavior;
import io.openbas.rest.inject.form.*;
Expand All @@ -36,6 +37,7 @@
import io.openbas.service.TagRuleService;
import io.openbas.telemetry.Tracing;
import io.openbas.utils.pagination.SearchPaginationInput;
import io.swagger.v3.oas.annotations.Operation;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
Expand All @@ -51,6 +53,7 @@
import org.springframework.security.access.annotation.Secured;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

Expand Down Expand Up @@ -200,17 +203,6 @@ public Inject updateInject(
return injectRepository.save(inject);
}

@Transactional(rollbackFor = Exception.class)
@PutMapping(INJECT_URI + "/{exerciseId}/{injectId}/bulk")
@PreAuthorize("isExercisePlanner(#exerciseId)")
public Inject bulkUpdateInject(
@PathVariable String exerciseId,
@PathVariable String injectId,
@Valid @RequestBody InjectInput input) {
Inject inject = bulkUpdateInject(injectId, input);
return injectRepository.save(inject);
}

// -- EXERCISES --

@LogExecutionTime
Expand Down Expand Up @@ -653,17 +645,6 @@ public Inject scenarioInject(
return injectRepository.findById(injectId).orElseThrow(ElementNotFoundException::new);
}

@Transactional(rollbackFor = Exception.class)
@PutMapping(SCENARIO_URI + "/{scenarioId}/injects/{injectId}/bulk")
@PreAuthorize("isScenarioPlanner(#scenarioId)")
public Inject bulkUpdateInjectForScenario(
@PathVariable String scenarioId,
@PathVariable String injectId,
@Valid @RequestBody InjectInput input) {
Inject inject = bulkUpdateInject(injectId, input);
return injectRepository.save(inject);
}

@Transactional(rollbackFor = Exception.class)
@PutMapping(SCENARIO_URI + "/{scenarioId}/injects/{injectId}")
@PreAuthorize("isScenarioPlanner(#scenarioId)")
Expand Down Expand Up @@ -708,6 +689,61 @@ public void deleteInjectForScenario(
this.injectRepository.deleteById(injectId);
}

@Operation(
description = "Bulk update of injects",
tags = {"Injects"})
@Transactional(rollbackFor = Exception.class)
@PutMapping(INJECT_URI)
@LogExecutionTime
@Tracing(name = "Bulk update of injects", layer = "api", operation = "PUT")
public List<Inject> bulkUpdateInject(@RequestBody @Valid final InjectBulkUpdateInputs input) {

// Control and format inputs
List<Inject> injectsToUpdate = getInjectsAndCheckInputForBulkProcessing(input);

// Bulk update
return this.injectService.bulkUpdateInject(injectsToUpdate, input.getUpdateOperations());
}

@Operation(
description = "Bulk delete of injects",
tags = {"injects-api"})
@Transactional(rollbackFor = Exception.class)
@DeleteMapping(INJECT_URI)
@LogExecutionTime
@Tracing(name = "Bulk delete of injects", layer = "api", operation = "DELETE")
public void bulkDelete(@RequestBody @Valid final InjectBulkProcessingInput input) {

// Control and format inputs
List<Inject> injectsToDelete = getInjectsAndCheckInputForBulkProcessing(input);

// Bulk delete
this.injectService.deleteAllByIds(injectsToDelete.stream().map(Inject::getId).toList());
}

/**
* Retrieve injects that match the search input and check that the user is allowed to bulk process
* them
*
* @param input The input for the bulk processing
* @return The list of injects to process
* @throws BadRequestException If the input is not correctly formatted
*/
private List<Inject> getInjectsAndCheckInputForBulkProcessing(InjectBulkProcessingInput input) {
// Control and format inputs
if ((CollectionUtils.isEmpty(input.getInjectIDsToProcess())
&& (input.getSearchPaginationInput() == null))
|| (!CollectionUtils.isEmpty(input.getInjectIDsToProcess())
&& (input.getSearchPaginationInput() != null))) {
throw new BadRequestException(
"Either inject_ids_to_process or search_pagination_input must be provided, and not both at the same time");
}

// Retrieve injects that match the search input and check that the user is allowed to bulk
// process them
return this.injectService.getInjectsAndCheckIsPlanner(input);
}

// -- PRIVATE --

private Inject updateInject(@NotBlank final String injectId, @NotNull InjectInput input) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
Expand Down Expand Up @@ -66,13 +65,6 @@ public Iterable<InjectOutput> scenarioInjectsSimple(
joinMap);
}

@DeleteMapping(SCENARIO_URI + "/{scenarioId}/injects")
@PreAuthorize("isScenarioPlanner(#scenarioId)")
public void deleteListOfInjectsForScenario(
@PathVariable final String scenarioId, @RequestBody List<String> injectIds) {
injectService.deleteAllByIds(injectIds);
}

@PostMapping("/api/scenario/{scenarioId}/injects/test")
public Page<InjectTestStatus> findAllScenarioInjectTests(
@PathVariable @NotBlank String scenarioId,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package io.openbas.rest.inject.form;

import com.fasterxml.jackson.annotation.JsonProperty;
import io.openbas.utils.pagination.SearchPaginationInput;
import java.util.List;
import lombok.Getter;
import lombok.Setter;

/** Represent the input of a bulk processing (delete and tests) calls for injects */
@Setter
@Getter
public class InjectBulkProcessingInput {

/**
* The search input, used to select the injects to update. Must be provided if injectIDsToDelete
* is not provided
*/
@JsonProperty("search_pagination_input")
private SearchPaginationInput searchPaginationInput;

/** The list of injects to process. Must be provided if searchPaginationInput is not provided */
@JsonProperty("inject_ids_to_process")
private List<String> injectIDsToProcess;

/** The list of injects to ignore from the search input */
@JsonProperty("inject_ids_to_ignore")
private List<String> injectIDsToIgnore;

/** The simulation or scenario ID to which the injects belong. */
@JsonProperty("simulation_or_scenario_id")
private String simulationOrScenarioId;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package io.openbas.rest.inject.form;

import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.List;
import lombok.Getter;
import lombok.Setter;

/** Represent the input of a bulk update call for injects */
@Setter
@Getter
public class InjectBulkUpdateInputs extends InjectBulkProcessingInput {

/** The operations to perform to update injects */
@JsonProperty("update_operations")
private List<InjectBulkUpdateOperation> updateOperations;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package io.openbas.rest.inject.form;

import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.List;
import lombok.Getter;
import lombok.Setter;

/** Represent an operation to perform on a list of injects to update them */
@Setter
@Getter
public class InjectBulkUpdateOperation {

/** The operations to perform to update injects */
@JsonProperty("operation")
private InjectBulkUpdateSupportedOperations operation;

/** The field to update in the injects */
@JsonProperty("field")
private InjectBulkUpdateSupportedFields field;

/** The values involved in the update operation for given field */
@JsonProperty("values")
private List<String> values;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package io.openbas.rest.inject.form;

import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Getter;

/** Represent the supported fields that can be bulk updated in injects */
@Getter
public enum InjectBulkUpdateSupportedFields {
@JsonProperty("assets")
ASSETS("assets"),
@JsonProperty("asset_groups")
ASSET_GROUPS("assetGroups"),
@JsonProperty("teams")
TEAMS("teams");

private final String value;

InjectBulkUpdateSupportedFields(final String value) {
this.value = value;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package io.openbas.rest.inject.form;

import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Getter;

/** Represent the supported operations that can be performed in a bulk update of injects */
@Getter
public enum InjectBulkUpdateSupportedOperations {
@JsonProperty("add")
ADD("ADD"),
@JsonProperty("remove")
REMOVE("REMOVE"),
@JsonProperty("replace")
REPLACE("REPLACE");

private final String value;

InjectBulkUpdateSupportedOperations(final String value) {
this.value = value;
}
}
Loading

0 comments on commit 3ace5a8

Please sign in to comment.