"); + // If we found a secured annotation + if (securedAnnotation != null) { + // We add the required role in the description + description += + "**Required role :** ***" + + String.join("*** or ***", securedAnnotation.value()) + + "***"; + } else if (annotation.needAuthenticated()) { + // If there are no secured annotation and we need to be authenticated + // Then we add all the existing role in the description + description += + "**Required role :** ***" + String.join("*** or ***", User.ALL_ROLES) + "***"; + } else { + // If no secured annotation and we don't need authentication, then we show that no roles are + // required + description += "**Required role :** none"; + } + + operation.setDescription(description + getSpecialRequirements(handlerMethod)); + } + return operation; + } + + private String getSpecialRequirements(HandlerMethod handlerMethod) { + String specialRequirement = StringUtils.EMPTY; + var preAuthorizeAnnotation = handlerMethod.getMethodAnnotation(PreAuthorize.class); + if (preAuthorizeAnnotation != null) { + specialRequirement += "
**Special Requirement :** "; + String preAuthorize = preAuthorizeAnnotation.value(); + if (preAuthorize.startsWith("isExercisePlanner") + || preAuthorize.startsWith("isSimulationPlanner")) { + specialRequirement += + "You need to be an admin or a planner of the simulation to call this endpoint"; + } else if (preAuthorize.startsWith("isExerciseObserver")) { + specialRequirement += + "You need to be an admin or an observer of the simulation to call this endpoint"; + } else if (preAuthorize.startsWith("isExercisePlayer")) { + specialRequirement += + "You need to be an admin or a player of the simulation to call this endpoint"; + } else if (preAuthorize.startsWith("isExerciseObserverOrPlayer")) { + specialRequirement += + "You need to be an admin, an observer or a player of the simulation to call this endpoint"; + } else if (preAuthorize.startsWith("isScenarioPlanner")) { + specialRequirement += + "You need to be an admin or a planner of the scenario to call this endpoint"; + } else if (preAuthorize.startsWith("isScenarioObserver")) { + specialRequirement += + "You need to be an admin or an observer of the scenario to call this endpoint"; + } else if (preAuthorize.startsWith("isPlanner")) { + specialRequirement += "You need to be an admin or a planner to call this endpoint"; + } else if (preAuthorize.startsWith("isObserver")) { + specialRequirement += "You need to be an admin or an observer to call this endpoint"; + } else if (preAuthorize.startsWith("isPlayer")) { + specialRequirement += "You need to be a player to call this endpoint"; + } + } + return specialRequirement; + } +} diff --git a/openbas-api/src/main/java/io/openbas/rest/helper/ValidationErrorBag.java b/openbas-api/src/main/java/io/openbas/rest/helper/ValidationErrorBag.java index fdacc1d291..c9299333c9 100644 --- a/openbas-api/src/main/java/io/openbas/rest/helper/ValidationErrorBag.java +++ b/openbas-api/src/main/java/io/openbas/rest/helper/ValidationErrorBag.java @@ -1,39 +1,35 @@ package io.openbas.rest.helper; +import io.swagger.v3.oas.annotations.media.Schema; import java.util.List; import java.util.Map; +import lombok.Data; +@Data class ValidationContent { + @Schema(description = "A list of errors") private List
- > errorMessages = Optional.empty();
if (ofNullable(executableInject.getExerciseId()).isPresent()) {
- errorMessages = getErrorMessagesPreExecution(executableInject.getExerciseId(), inject);
+ checkErrorMessagesPreExecution(executableInject.getExerciseId(), inject);
}
- if (errorMessages != null && errorMessages.isPresent()) {
- InjectStatus finalStatus = injectStatusService.failInjectStatus(inject.getId(), null);
- errorMessages
- .get()
- .forEach(errorMsg -> finalStatus.addErrorTrace(errorMsg, ExecutionTraceAction.COMPLETE));
- injectStatusRepository.save(finalStatus);
- } else {
- setInjectStatusAndExecuteInject(executableInject, inject);
+ if (!inject.isReady()) {
+ throw new UnsupportedOperationException(
+ "The inject is not ready to be executed (missing mandatory fields)");
}
- }
-
- private void setInjectStatusAndExecuteInject(ExecutableInject executableInject, Inject inject) {
- inject
- .getInjectorContract()
- .ifPresentOrElse(
- injectorContract -> {
- if (!inject.isReady()) {
- injectStatusService.failInjectStatus(
- inject.getId(),
- "The inject is not ready to be executed (missing mandatory fields)");
- return;
- }
-
- Injector externalInjector =
- injectorRepository
- .findByType(injectorContract.getInjector().getType())
- .orElseThrow();
- LOGGER.log(Level.INFO, "Executing inject " + inject.getInject().getTitle());
- // Executor logics
- ExecutableInject newExecutableInject = executableInject;
-
- InjectStatus injectStatus =
- injectStatusService.initializeInjectStatus(
- inject.getId(), ExecutionStatus.EXECUTING, null);
- if (Boolean.TRUE.equals(injectorContract.getNeedsExecutor())) {
- // Status
- inject.setStatus(injectStatus);
- try {
- newExecutableInject =
- this.executionExecutorService.launchExecutorContext(executableInject, inject);
- } catch (Exception e) {
- injectStatusService.failInjectStatus(inject.getId(), e.getMessage());
- return;
- }
- }
- if (externalInjector.isExternal()) {
- executeExternal(newExecutableInject);
- } else {
- executeInternal(newExecutableInject);
- }
- },
- () ->
- injectStatusService.failInjectStatus(
- inject.getId(), "Inject does not have a contract"));
+ LOGGER.log(Level.INFO, "Executing inject " + inject.getInject().getTitle());
+ this.executor.execute(executableInject);
}
/**
@@ -214,7 +111,8 @@ private void setInjectStatusAndExecuteInject(ExecutableInject executableInject,
* @param inject the inject to check
* @return an optional of list of error message
*/
- private Optional
- > getErrorMessagesPreExecution(String exerciseId, Inject inject) {
+ private void checkErrorMessagesPreExecution(String exerciseId, Inject inject)
+ throws ErrorMessagesPreExecutionException {
List
- > getErrorMessagesPreExecution(String exerciseId, I
Map
- > getErrorMessagesPreExecution(String exerciseId, I
Expression exp = parser.parseExpression(expressionToEvaluate);
boolean canBeExecuted = Boolean.TRUE.equals(exp.getValue(mapCondition, Boolean.class));
if (!canBeExecuted) {
- if (results == null) {
- results = new ArrayList<>();
- results.add(
+ if (errorMessages.isEmpty()) {
+ errorMessages.add(
"This inject depends on other injects expectations that are not met. The following conditions were not as expected : ");
}
- results.addAll(
+ errorMessages.addAll(
labelFromCondition(
injectDependency.getCompositeId().getInjectParent(),
injectDependency.getInjectDependencyCondition()));
}
}
- return results == null ? Optional.empty() : Optional.of(results);
+ if (!errorMessages.isEmpty()) {
+ throw new ErrorMessagesPreExecutionException(errorMessages);
+ }
}
- return Optional.empty();
}
/**
@@ -271,18 +169,13 @@ private Optional
- > getErrorMessagesPreExecution(String exerciseId, I
*/
private @NotNull Map
. + // TODO : convert properly the whole cell into HTML including formatting (bold, ...) + if (mapFieldByKey.get(ruleAttribute.getName()).get("richText") != null + && mapFieldByKey.get(ruleAttribute.getName()).get("richText").asBoolean()) { + columnValue = columnValue.replaceAll("\n", "
"); + } + return columnValue; + } + + /** + * Returns a date out of an InjectTime object with a time pattern + * + * @param injectTime the object representing a date in the cells + * @param timePattern a pattern to use to find out what value it is + * @return the date + */ + public static Temporal getInjectDate(InjectTime injectTime, String timePattern) { + DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ISO_DATE_TIME; + if (timePattern != null && !timePattern.isEmpty()) { + dateTimeFormatter = DateTimeFormatter.ofPattern(timePattern); + try { + return LocalDateTime.parse(injectTime.getUnformattedDate(), dateTimeFormatter); + } catch (DateTimeParseException firstException) { + try { + return LocalTime.parse(injectTime.getUnformattedDate(), dateTimeFormatter); + } catch (DateTimeParseException exception) { + // This is a "probably" a relative date + } + } + } else { + try { + return LocalDateTime.parse(injectTime.getUnformattedDate(), dateTimeFormatter); + } catch (DateTimeParseException firstException) { + // The date is not in ISO_DATE_TIME. Trying just the ISO_TIME + dateTimeFormatter = DateTimeFormatter.ISO_TIME; + try { + return LocalTime.parse(injectTime.getUnformattedDate(), dateTimeFormatter); + } catch (DateTimeParseException secondException) { + // Neither ISO_DATE_TIME nor ISO_TIME + } + } + } + injectTime.setFormatter(dateTimeFormatter); + return null; + } +} diff --git a/openbas-api/src/main/java/io/openbas/utils/InjectMapper.java b/openbas-api/src/main/java/io/openbas/utils/InjectMapper.java index d866c3191c..0f3bdb4ed6 100644 --- a/openbas-api/src/main/java/io/openbas/utils/InjectMapper.java +++ b/openbas-api/src/main/java/io/openbas/utils/InjectMapper.java @@ -2,10 +2,9 @@ import io.openbas.database.model.*; import io.openbas.rest.atomic_testing.form.*; -import java.util.List; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; +import io.openbas.rest.inject.output.InjectTestStatusOutput; +import java.util.*; +import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; import org.springframework.context.ApplicationContext; import org.springframework.stereotype.Component; @@ -97,23 +96,93 @@ private PayloadSimple toPayloadSimple(Optional
Test", result); + } + + @DisplayName("Test get a string cell and keep it as plain text") + @Test + void testExtractWithoutConvertingCellAsHTML() throws Exception { + // -- PREPARE -- + cell.setCellValue("Test\nTest"); + RuleAttribute ruleAttribute = MockMapperUtils.createRuleAttribute(); + ruleAttribute.setColumns("A"); + json.put("richText", false); + // -- EXECUTE -- + String result = + InjectImportUtils.extractAndConvertStringColumnValue( + row, ruleAttribute, Map.of("Test", json)); + + // -- ASSERT -- + assertNotNull(result); + assertEquals("Test\nTest", result); + } + + @DisplayName("Test get inject date without pattern but with an ISO_DATE_TIME format") + @Test + void testGetInjectDateWithoutPattern() throws Exception { + // -- PREPARE -- + InjectTime injectTime = new InjectTime(); + injectTime.setUnformattedDate(LocalDateTime.of(2025, 1, 1, 12, 0, 0).toString()); + // -- EXECUTE -- + Temporal result = InjectImportUtils.getInjectDate(injectTime, null); + + // -- ASSERT -- + assertNotNull(result); + assertEquals(LocalDateTime.of(2025, 1, 1, 12, 0, 0), result); + } + + @DisplayName("Test get inject time without pattern but with an ISO_TIME format") + @Test + void testGetInjectTimeWithoutPattern() throws Exception { + // -- PREPARE -- + InjectTime injectTime = new InjectTime(); + injectTime.setUnformattedDate(LocalTime.of(12, 0, 0).format(DateTimeFormatter.ISO_TIME)); + // -- EXECUTE -- + Temporal result = InjectImportUtils.getInjectDate(injectTime, null); + + // -- ASSERT -- + assertNotNull(result); + assertEquals(LocalTime.of(12, 0, 0), result); + } + + @DisplayName("Test get inject time without pattern and in an unknown format") + @Test + void testGetInjectTimeUndetected() throws Exception { + // -- PREPARE -- + InjectTime injectTime = new InjectTime(); + injectTime.setUnformattedDate("13 heures et demi"); + // -- EXECUTE -- + Temporal result = InjectImportUtils.getInjectDate(injectTime, null); + + // -- ASSERT -- + assertNull(result); + } + + @DisplayName("Test get inject date and time with a specified pattern") + @Test + void testGetInjectDateTimeWithPattern() throws Exception { + // -- PREPARE -- + InjectTime injectTime = new InjectTime(); + injectTime.setUnformattedDate("25/01/20 13h05:52"); + // -- EXECUTE -- + Temporal result = InjectImportUtils.getInjectDate(injectTime, "yy/MM/dd HH'h'mm:ss"); + + // -- ASSERT -- + assertNotNull(result); + assertEquals(LocalDateTime.of(2025, 1, 20, 13, 5, 52), result); + } + + @DisplayName("Test get inject time with a specified pattern") + @Test + void testGetInjectTimeWithPattern() throws Exception { + // -- PREPARE -- + InjectTime injectTime = new InjectTime(); + injectTime.setUnformattedDate("13h05:52"); + // -- EXECUTE -- + Temporal result = InjectImportUtils.getInjectDate(injectTime, "HH'h'mm:ss"); + + // -- ASSERT -- + assertNotNull(result); + assertEquals(LocalTime.of(13, 5, 52), result); + } + + @DisplayName("Test get inject time with a specified pattern that does not match") + @Test + void testGetInjectTimeUndetectedWithTimePattern() throws Exception { + // -- PREPARE -- + InjectTime injectTime = new InjectTime(); + injectTime.setUnformattedDate("13 heures et demi"); + // -- EXECUTE -- + Temporal result = InjectImportUtils.getInjectDate(injectTime, "HH'h'mm:ss"); + + // -- ASSERT -- + assertNull(result); + } +} diff --git a/openbas-api/src/test/java/io/openbas/utils/fixtures/AgentFixture.java b/openbas-api/src/test/java/io/openbas/utils/fixtures/AgentFixture.java index 8083207ab0..2f6e5505db 100644 --- a/openbas-api/src/test/java/io/openbas/utils/fixtures/AgentFixture.java +++ b/openbas-api/src/test/java/io/openbas/utils/fixtures/AgentFixture.java @@ -6,13 +6,18 @@ public class AgentFixture { - public static Agent createAgent(Asset asset, String externalReference) { + public static Agent createDefaultAgent() { Agent agent = new Agent(); agent.setExecutedByUser(Agent.ADMIN_SYSTEM_WINDOWS); agent.setPrivilege(Agent.PRIVILEGE.admin); agent.setDeploymentMode(Agent.DEPLOYMENT_MODE.service); - agent.setAsset(asset); agent.setLastSeen(Instant.now()); + return agent; + } + + public static Agent createAgent(Asset asset, String externalReference) { + Agent agent = createDefaultAgent(); + agent.setAsset(asset); agent.setExternalReference(externalReference); return agent; } diff --git a/openbas-api/src/test/java/io/openbas/utils/fixtures/InjectStatusFixture.java b/openbas-api/src/test/java/io/openbas/utils/fixtures/InjectStatusFixture.java index 977bf186bd..d853e9fd13 100644 --- a/openbas-api/src/test/java/io/openbas/utils/fixtures/InjectStatusFixture.java +++ b/openbas-api/src/test/java/io/openbas/utils/fixtures/InjectStatusFixture.java @@ -1,5 +1,7 @@ package io.openbas.utils.fixtures; +import static io.openbas.database.model.Command.COMMAND_TYPE; + import io.openbas.database.model.ExecutionStatus; import io.openbas.database.model.InjectStatus; import io.openbas.database.model.PayloadCommandBlock; @@ -12,9 +14,12 @@ public class InjectStatusFixture { public static InjectStatus createDefaultInjectStatus() { InjectStatus injectStatus = new InjectStatus(); injectStatus.setTrackingSentDate(Instant.now()); - injectStatus.setName(ExecutionStatus.SUCCESS); + injectStatus.setName(ExecutionStatus.PENDING); injectStatus.setPayloadOutput( new StatusPayload( + null, + null, + COMMAND_TYPE, null, null, null, diff --git a/openbas-api/src/test/java/io/openbas/utils/fixtures/composers/AgentComposer.java b/openbas-api/src/test/java/io/openbas/utils/fixtures/composers/AgentComposer.java new file mode 100644 index 0000000000..70e783ccad --- /dev/null +++ b/openbas-api/src/test/java/io/openbas/utils/fixtures/composers/AgentComposer.java @@ -0,0 +1,41 @@ +package io.openbas.utils.fixtures.composers; + +import io.openbas.database.model.Agent; +import io.openbas.database.repository.AgentRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class AgentComposer extends ComposerBase
-
- {endpointValues?.map((endpoint) => {
- return (
-
-
+ {endpoints?.map((endpoint) => {
+ return (
+