Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[backend] Add the default Assets logic to scenario creation and update #2161

Merged
merged 18 commits into from
Jan 7, 2025
Original file line number Diff line number Diff line change
Expand Up @@ -401,12 +401,13 @@
@PreAuthorize("isExercisePlanner(#exerciseId)")
@Transactional(rollbackOn = Exception.class)
public Exercise updateExerciseInformation(
@PathVariable String exerciseId, @Valid @RequestBody ExerciseInput input) {
@PathVariable String exerciseId, @Valid @RequestBody UpdateExerciseInput input) {
Exercise exercise =
exerciseRepository.findById(exerciseId).orElseThrow(ElementNotFoundException::new);
Set<Tag> currentTagList = exercise.getTags();

Check warning on line 407 in openbas-api/src/main/java/io/openbas/rest/exercise/ExerciseApi.java

View check run for this annotation

Codecov / codecov/patch

openbas-api/src/main/java/io/openbas/rest/exercise/ExerciseApi.java#L407

Added line #L407 was not covered by tests
exercise.setTags(iterableToSet(this.tagRepository.findAllById(input.getTagIds())));
exercise.setUpdateAttributes(input);
return exerciseRepository.save(exercise);
return exerciseService.updateExercice(exercise, currentTagList, input.isApplyTagRule());

Check warning on line 410 in openbas-api/src/main/java/io/openbas/rest/exercise/ExerciseApi.java

View check run for this annotation

Codecov / codecov/patch

openbas-api/src/main/java/io/openbas/rest/exercise/ExerciseApi.java#L410

Added line #L410 was not covered by tests
}

@PutMapping(EXERCISE_URI + "/{exerciseId}/start_date")
Expand All @@ -432,8 +433,9 @@
@PathVariable String exerciseId, @Valid @RequestBody ExerciseUpdateTagsInput input) {
Exercise exercise =
exerciseRepository.findById(exerciseId).orElseThrow(ElementNotFoundException::new);
Set<Tag> currentTagList = exercise.getTags();

Check warning on line 436 in openbas-api/src/main/java/io/openbas/rest/exercise/ExerciseApi.java

View check run for this annotation

Codecov / codecov/patch

openbas-api/src/main/java/io/openbas/rest/exercise/ExerciseApi.java#L436

Added line #L436 was not covered by tests
exercise.setTags(iterableToSet(tagRepository.findAllById(input.getTagIds())));
return exerciseRepository.save(exercise);
return exerciseService.updateExercice(exercise, currentTagList, input.isApplyTagRule());

Check warning on line 438 in openbas-api/src/main/java/io/openbas/rest/exercise/ExerciseApi.java

View check run for this annotation

Codecov / codecov/patch

openbas-api/src/main/java/io/openbas/rest/exercise/ExerciseApi.java#L438

Added line #L438 was not covered by tests
}

@PutMapping(EXERCISE_URI + "/{exerciseId}/logos")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,7 @@

@JsonProperty("exercise_tags")
private List<String> tagIds = new ArrayList<>();

@JsonProperty("apply_tag_rule")

Check warning on line 16 in openbas-api/src/main/java/io/openbas/rest/exercise/form/ExerciseUpdateTagsInput.java

View check run for this annotation

Codecov / codecov/patch

openbas-api/src/main/java/io/openbas/rest/exercise/form/ExerciseUpdateTagsInput.java#L16

Added line #L16 was not covered by tests
private boolean applyTagRule = false;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package io.openbas.rest.exercise.form;

import static io.openbas.config.AppConfig.*;

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

@Getter
@Setter
@Data
public class UpdateExerciseInput extends ExerciseInput {
@JsonProperty("apply_tag_rule")
private boolean applyTagRule = false;
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@
import io.openbas.rest.exercise.form.ExercisesGlobalScoresInput;
import io.openbas.rest.exercise.response.ExercisesGlobalScoresOutput;
import io.openbas.rest.inject.service.InjectDuplicateService;
import io.openbas.rest.inject.service.InjectService;
import io.openbas.service.GrantService;
import io.openbas.service.TagRuleService;
import io.openbas.service.TeamService;
import io.openbas.service.VariableService;
import io.openbas.utils.AtomicTestingUtils;
Expand Down Expand Up @@ -68,6 +70,8 @@ public class ExerciseService {
private final InjectDuplicateService injectDuplicateService;
private final TeamService teamService;
private final VariableService variableService;
private final TagRuleService tagRuleService;
private final InjectService injectService;

private final ExerciseMapper exerciseMapper;
private final InjectMapper injectMapper;
Expand Down Expand Up @@ -614,4 +618,43 @@ public Iterable<Team> removeTeams(
this.lessonsCategoryRepository.removeTeamsForExercise(exerciseId, teamIds);
return teamRepository.findAllById(teamIds);
}

/**
* Update the simulation and each of the injects to add/remove default assets
*
* @param exercise
* @param currentTags list of the tags before the update
* @return
*/
@Transactional
public Exercise updateExercice(
@NotNull final Exercise exercise, @NotNull final Set<Tag> currentTags, boolean applyRule) {
if (applyRule) {
// Get assets from the TagRule of the added tags
List<Asset> defaultAssetsToAdd =
tagRuleService.getAssetsFromTagIds(
exercise.getTags().stream()
.filter(tag -> !currentTags.contains(tag))
.map(Tag::getId)
.toList());

// Get assets from the TagRule of the removed tags
List<Asset> defaultAssetsToRemove =
tagRuleService.getAssetsFromTagIds(
currentTags.stream()
.filter(tag -> !exercise.getTags().contains(tag))
.map(Tag::getId)
.toList());

// Add/remove the default assets to/from the injects
exercise
.getInjects()
.forEach(
inject ->
injectService.applyDefaultAssetsToInject(
inject.getId(), defaultAssetsToAdd, defaultAssetsToRemove));
}
exercise.setUpdatedAt(now());
return exerciseRepository.save(exercise);
}
}
22 changes: 17 additions & 5 deletions openbas-api/src/main/java/io/openbas/rest/inject/InjectApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,15 @@
import io.openbas.rest.inject.service.InjectService;
import io.openbas.service.InjectSearchService;
import io.openbas.service.ScenarioService;
import io.openbas.service.TagRuleService;
import io.openbas.telemetry.Tracing;
import io.openbas.utils.pagination.SearchPaginationInput;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
import lombok.RequiredArgsConstructor;
Expand Down Expand Up @@ -84,6 +83,7 @@ public class InjectApi extends RestBehavior {
private final ExecutableInjectService executableInjectService;
private final InjectSearchService injectSearchService;
private final InjectDuplicateService injectDuplicateService;
private final TagRuleService tagRuleService;

// -- INJECTS --

Expand Down Expand Up @@ -348,7 +348,13 @@ public Inject createInjectForExercise(
.toList());
}
inject.setTeams(fromIterable(teamRepository.findAllById(input.getTeams())));
inject.setAssets(fromIterable(assetService.assets(input.getAssets())));

// add default assets
inject.setAssets(
this.tagRuleService.applyTagRuleToInjectCreation(
exercise.getTags().stream().map(Tag::getId).toList(),
assetService.assets(input.getAssets())));

inject.setAssetGroups(fromIterable(assetGroupService.assetGroups(input.getAssetGroups())));
inject.setTags(iterableToSet(tagRepository.findAllById(input.getTagIds())));
List<InjectDocument> injectDocuments =
Expand Down Expand Up @@ -582,7 +588,13 @@ public Inject createInjectForScenario(
.toList());
}
inject.setTeams(fromIterable(teamRepository.findAllById(input.getTeams())));
inject.setAssets(fromIterable(assetService.assets(input.getAssets())));

// add default assets
inject.setAssets(
this.tagRuleService.applyTagRuleToInjectCreation(
scenario.getTags().stream().map(Tag::getId).toList(),
assetService.assets(input.getAssets())));

inject.setAssetGroups(fromIterable(assetGroupService.assetGroups(input.getAssetGroups())));
inject.setTags(iterableToSet(tagRepository.findAllById(input.getTagIds())));
List<InjectDocument> injectDocuments =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,7 @@

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import io.openbas.database.model.ExecutionStatus;
import io.openbas.database.model.Inject;
import io.openbas.database.model.InjectDocument;
import io.openbas.database.model.InjectStatus;
import io.openbas.database.model.*;
import io.openbas.database.repository.InjectDocumentRepository;
import io.openbas.database.repository.InjectRepository;
import io.openbas.database.repository.InjectStatusRepository;
Expand All @@ -22,7 +19,10 @@
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import java.time.Instant;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import lombok.RequiredArgsConstructor;
import lombok.extern.java.Log;
Expand Down Expand Up @@ -141,6 +141,47 @@ public void delete(String id) {
injectRepository.deleteById(id);
}

/**
* Update an inject with default assets
*
* @param injectId
* @param defaultAssetsToAdd
* @param defaultAssetsToRemove
* @return
*/
@Transactional
public Inject applyDefaultAssetsToInject(
final String injectId,
final List<Asset> defaultAssetsToAdd,
final List<Asset> defaultAssetsToRemove) {

// fetch the inject
Inject inject =
this.injectRepository.findById(injectId).orElseThrow(ElementNotFoundException::new);

// remove/add default assets and remove duplicates
List<Asset> currentAssets = inject.getAssets();
// Get the Id of the assets to remove and filter the assets that are in both lists
List<String> assetIdsToRemove =
defaultAssetsToRemove.stream()
.filter(asset -> !defaultAssetsToAdd.contains(asset))
.map(Asset::getId)
.toList();
Set<String> uniqueAssetsIds = new HashSet<>();
List<Asset> newListOfAssets =
Stream.concat(currentAssets.stream(), defaultAssetsToAdd.stream())
.filter(asset -> !assetIdsToRemove.contains(asset.getId()))
.filter(asset -> uniqueAssetsIds.add(asset.getId()))
.collect(Collectors.toList());

if (new HashSet<>(currentAssets).equals(new HashSet<>(newListOfAssets))) {
return inject;
} else {
inject.setAssets(newListOfAssets);
return this.injectRepository.save(inject);
}
}

private Inject findAndDuplicateInject(String id) {
Inject injectOrigin = injectRepository.findById(id).orElseThrow(ElementNotFoundException::new);
return InjectUtils.duplicateInject(injectOrigin);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import jakarta.validation.constraints.NotNull;
import java.io.IOException;
import java.util.List;
import java.util.Set;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
Expand Down Expand Up @@ -100,11 +101,12 @@
@PreAuthorize("isScenarioPlanner(#scenarioId)")
public Scenario updateScenario(
@PathVariable @NotBlank final String scenarioId,
@Valid @RequestBody final ScenarioInput input) {
@Valid @RequestBody final UpdateScenarioInput input) {
Scenario scenario = this.scenarioService.scenario(scenarioId);
Set<Tag> currentTagList = scenario.getTags();
scenario.setUpdateAttributes(input);
scenario.setTags(iterableToSet(this.tagRepository.findAllById(input.getTagIds())));
return this.scenarioService.updateScenario(scenario);
return this.scenarioService.updateScenario(scenario, currentTagList, input.isApplyTagRule());
}

@PutMapping(SCENARIO_URI + "/{scenarioId}/information")
Expand All @@ -131,8 +133,9 @@
@PathVariable @NotBlank final String scenarioId,
@Valid @RequestBody final ScenarioUpdateTagsInput input) {
Scenario scenario = this.scenarioService.scenario(scenarioId);
Set<Tag> currentTagList = scenario.getTags();

Check warning on line 136 in openbas-api/src/main/java/io/openbas/rest/scenario/ScenarioApi.java

View check run for this annotation

Codecov / codecov/patch

openbas-api/src/main/java/io/openbas/rest/scenario/ScenarioApi.java#L136

Added line #L136 was not covered by tests
scenario.setTags(iterableToSet(this.tagRepository.findAllById(input.getTagIds())));
return scenarioService.updateScenario(scenario);
return this.scenarioService.updateScenario(scenario, currentTagList, input.isApplyTagRule());

Check warning on line 138 in openbas-api/src/main/java/io/openbas/rest/scenario/ScenarioApi.java

View check run for this annotation

Codecov / codecov/patch

openbas-api/src/main/java/io/openbas/rest/scenario/ScenarioApi.java#L138

Added line #L138 was not covered by tests
}

// -- EXPORT --
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,7 @@

@JsonProperty("scenario_tags")
private List<String> tagIds = new ArrayList<>();

@JsonProperty("apply_tag_rule")

Check warning on line 16 in openbas-api/src/main/java/io/openbas/rest/scenario/form/ScenarioUpdateTagsInput.java

View check run for this annotation

Codecov / codecov/patch

openbas-api/src/main/java/io/openbas/rest/scenario/form/ScenarioUpdateTagsInput.java#L16

Added line #L16 was not covered by tests
private boolean applyTagRule = false;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package io.openbas.rest.scenario.form;

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

@Data
@Getter
public class UpdateScenarioInput extends ScenarioInput {
@JsonProperty("apply_tag_rule")
private boolean applyTagRule = false;
}
42 changes: 42 additions & 0 deletions openbas-api/src/main/java/io/openbas/service/ScenarioService.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import io.openbas.rest.exercise.exports.VariableWithValueMixin;
import io.openbas.rest.exercise.form.ExerciseSimple;
import io.openbas.rest.inject.service.InjectDuplicateService;
import io.openbas.rest.inject.service.InjectService;
import io.openbas.rest.scenario.export.ScenarioExportMixins;
import io.openbas.rest.scenario.export.ScenarioFileExport;
import io.openbas.rest.scenario.form.ScenarioSimple;
Expand Down Expand Up @@ -102,6 +103,9 @@ public class ScenarioService {
private final TeamService teamService;
private final FileService fileService;
private final InjectDuplicateService injectDuplicateService;
private final TagRuleService tagRuleService;
private final InjectService injectService;

private final InjectRepository injectRepository;
private final LessonsCategoryRepository lessonsCategoryRepository;

Expand Down Expand Up @@ -290,6 +294,44 @@ public ExerciseSimple latestExerciseByExternalReference(
}

public Scenario updateScenario(@NotNull final Scenario scenario) {
return this.updateScenario(scenario, null, false);
}

/**
* Update the scenario and each of the injects to add/remove default assets
*
* @param scenario
* @param currentTags list of the tags before the update
* @return
*/
@Transactional
public Scenario updateScenario(
@NotNull final Scenario scenario, Set<Tag> currentTags, boolean applyRule) {
if (applyRule) {
// Get assets from the TagRule of the added tags
List<Asset> defaultAssetsToAdd =
tagRuleService.getAssetsFromTagIds(
scenario.getTags().stream()
.filter(tag -> !currentTags.contains(tag))
.map(Tag::getId)
.toList());

// Get assets from the TagRule of the removed tags
List<Asset> defaultAssetsToRemove =
tagRuleService.getAssetsFromTagIds(
currentTags.stream()
.filter(tag -> !scenario.getTags().contains(tag))
.map(Tag::getId)
.toList());

// Add/remove the default assets to/from the injects
scenario
.getInjects()
.forEach(
inject ->
injectService.applyDefaultAssetsToInject(
inject.getId(), defaultAssetsToAdd, defaultAssetsToRemove));
}
heditar marked this conversation as resolved.
Show resolved Hide resolved
scenario.setUpdatedAt(now());
return this.scenarioRepository.save(scenario);
}
Expand Down
Loading
Loading