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] adding TagRule apis/repo Issue/1998 #2122

Merged
merged 36 commits into from
Jan 3, 2025
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
ab2b9dc
repo+api
heditar Dec 19, 2024
16bd922
fixed CreateInject imports
heditar Dec 19, 2024
4074944
fixed CreateInject imports
heditar Dec 19, 2024
def8373
api+repo+test
heditar Dec 23, 2024
005a612
apply spotless
heditar Dec 23, 2024
a610f46
add tagrule mapper
heditar Dec 23, 2024
e81ded6
add tagrule mapper
heditar Dec 23, 2024
8a27fc0
fixed migration file
heditar Dec 23, 2024
9c5d1a8
apply spotless
heditar Dec 23, 2024
b35e671
change exception to ElementNotFoundException
heditar Dec 23, 2024
1eeec11
change to mutable list for hibernate
heditar Dec 23, 2024
5eb41c4
change to orelseget
heditar Dec 24, 2024
2e33547
added on delete cascade
heditar Dec 24, 2024
35ff5ae
Merge branch 'release/1.11.0' into issue/1998
heditar Dec 24, 2024
4279a37
spotless
heditar Dec 24, 2024
baa57af
spotless
heditar Dec 24, 2024
79f6e9f
spotless
heditar Dec 24, 2024
0f1742c
fix unit tests
heditar Dec 24, 2024
099c08c
spotless
heditar Dec 24, 2024
1f87dfb
added default tag color + index on tag id
heditar Dec 27, 2024
4f410dc
fixed unit tests
heditar Dec 30, 2024
f130f33
fixed pr comments
heditar Jan 2, 2025
de9360d
added mvc tests
heditar Jan 2, 2025
125315f
spotless
heditar Jan 2, 2025
25e3e91
Merge branch 'release/1.11.0' into issue/1998
heditar Jan 2, 2025
de3132b
fixed tests
heditar Jan 2, 2025
1ecb1a5
spotless
heditar Jan 2, 2025
31dd72d
Merge branch 'release/1.11.0' into issue/1998
heditar Jan 2, 2025
b3e3f04
changed migration number
heditar Jan 2, 2025
e6103c6
fixed unit test
heditar Jan 2, 2025
7072ad9
fixed unit test
heditar Jan 2, 2025
448b0a3
spotless
heditar Jan 2, 2025
9f04092
Merge branch 'release/1.11.0' into issue/1998
heditar Jan 2, 2025
3a2e029
updated api tests
heditar Jan 3, 2025
8872153
updated mapper to instance
heditar Jan 3, 2025
1fa9a8d
Merge branch 'release/1.11.0' into issue/1998
heditar Jan 3, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions openbas-api/src/main/java/io/openbas/migration/V3_54__TagRule.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package io.openbas.migration;

import java.sql.Connection;
import java.sql.Statement;
import org.flywaydb.core.api.migration.BaseJavaMigration;
import org.flywaydb.core.api.migration.Context;
import org.springframework.stereotype.Component;

@Component
public class V3_54__TagRule extends BaseJavaMigration {

@Override
public void migrate(Context context) throws Exception {
Connection connection = context.getConnection();
Statement select = connection.createStatement();
// Create relations between contracts and attack_patterns
heditar marked this conversation as resolved.
Show resolved Hide resolved
select.execute(
"""
CREATE TABLE tag_rules (
tag_rule_id varchar(255) not null,
tag_id varchar(255) not null
constraint tag_id_fk
references tags,
primary key (tag_rule_id)
);
""");

select.execute(
"""
CREATE TABLE tag_rule_assets (
tag_rule_id varchar(255) not null
constraint tag_rule_id_fk
references tag_rules,
asset_id varchar(255) not null
constraint asset_id_fk
references assets
on delete cascade,
primary key (tag_rule_id, asset_id)
);
""");
}
}
91 changes: 91 additions & 0 deletions openbas-api/src/main/java/io/openbas/rest/tag_rule/TagRuleApi.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package io.openbas.rest.tag_rule;

import static io.openbas.database.model.User.ROLE_ADMIN;

import io.openbas.aop.LogExecutionTime;
import io.openbas.rest.helper.RestBehavior;
import io.openbas.rest.tag_rule.form.TagRuleInput;
import io.openbas.rest.tag_rule.form.TagRuleMapper;
import io.openbas.rest.tag_rule.form.TagRuleOutput;
import io.openbas.service.TagRuleService;
import io.openbas.utils.pagination.SearchPaginationInput;
import io.swagger.v3.oas.annotations.Operation;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;
import java.util.List;
import org.springframework.data.domain.Page;
import org.springframework.security.access.annotation.Secured;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

@RestController
public class TagRuleApi extends RestBehavior {

public static final String TAG_RULE_URI = "/api/tag-rules";
private final TagRuleService tagRuleService;

public TagRuleApi(TagRuleService tagRuleService) {
super();
this.tagRuleService = tagRuleService;
}

@LogExecutionTime
@GetMapping(TagRuleApi.TAG_RULE_URI + "/{tagRuleId}")
public TagRuleOutput findTagRule(@PathVariable @NotBlank final String tagRuleId) {
heditar marked this conversation as resolved.
Show resolved Hide resolved
return tagRuleService.findById(tagRuleId).map(TagRuleMapper::toTagRuleOutput).orElse(null);
heditar marked this conversation as resolved.
Show resolved Hide resolved
}

@LogExecutionTime
@GetMapping(TagRuleApi.TAG_RULE_URI)
@Operation(summary = "Get All TagRules")
public List<TagRuleOutput> tags() {
return tagRuleService.findAll().stream().map(TagRuleMapper::toTagRuleOutput).toList();
}

@Secured(ROLE_ADMIN)
@LogExecutionTime
@DeleteMapping(TagRuleApi.TAG_RULE_URI + "/{tagRuleId}")
@Transactional(rollbackFor = Exception.class)
@Operation(summary = "Delete TagRule")
public void deleteTagRule(@PathVariable @NotBlank final String tagRuleId) {
this.tagRuleService.deleteTagRule(tagRuleId);
}

@Secured(ROLE_ADMIN)
@LogExecutionTime
@PostMapping(TagRuleApi.TAG_RULE_URI)
@Transactional(rollbackFor = Exception.class)
@Operation(
summary = "Create TagRule",
description = "If the Tag doesn't exist, it will be created")
heditar marked this conversation as resolved.
Show resolved Hide resolved
public TagRuleOutput createTagRule(@Valid @RequestBody final TagRuleInput input) {
return TagRuleMapper.toTagRuleOutput(
this.tagRuleService.createTagRule(input.getTagName(), input.getAssets()));
}

@Secured(ROLE_ADMIN)
@LogExecutionTime
@PutMapping(TagRuleApi.TAG_RULE_URI + "/{tagRuleId}")
@Transactional(rollbackFor = Exception.class)
@Operation(
summary = "Update TagRule",
description = "If the Tag doesn't exist, it will be created")
public TagRuleOutput updateTagRule(
@PathVariable @NotBlank final String tagRuleId,
@Valid @RequestBody final TagRuleInput input) {
return TagRuleMapper.toTagRuleOutput(
this.tagRuleService.updateTagRule(tagRuleId, input.getTagName(), input.getAssets()));
}

@LogExecutionTime
@PostMapping(TagRuleApi.TAG_RULE_URI + "/search")
@Operation(
summary = "Search TagRule",
description = "Tries to connect to dependencies (DB/Minio/RabbitMQ)")
heditar marked this conversation as resolved.
Show resolved Hide resolved
public Page<TagRuleOutput> searchTagRules(
@RequestBody @Valid SearchPaginationInput searchPaginationInput) {
return this.tagRuleService
.searchTagRule(searchPaginationInput)
.map(TagRuleMapper::toTagRuleOutput);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package io.openbas.rest.tag_rule.form;

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

import com.fasterxml.jackson.annotation.JsonProperty;
import jakarta.validation.constraints.NotBlank;
import java.util.ArrayList;
import java.util.List;
import lombok.Builder;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.extern.jackson.Jacksonized;

@Builder(toBuilder = true)
@Getter
@Jacksonized
@EqualsAndHashCode
public class TagRuleInput {
@NotBlank(message = MANDATORY_MESSAGE)
@JsonProperty("tag_name")
private String tagName;

@JsonProperty("tag_rule_assets")
private List<String> assets = new ArrayList<>();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package io.openbas.rest.tag_rule.form;

import io.openbas.database.model.Asset;
import io.openbas.database.model.TagRule;
import java.util.stream.Collectors;

public class TagRuleMapper {

Check warning on line 7 in openbas-api/src/main/java/io/openbas/rest/tag_rule/form/TagRuleMapper.java

View check run for this annotation

Codecov / codecov/patch

openbas-api/src/main/java/io/openbas/rest/tag_rule/form/TagRuleMapper.java#L7

Added line #L7 was not covered by tests
heditar marked this conversation as resolved.
Show resolved Hide resolved
public static TagRuleOutput toTagRuleOutput(final TagRule tagRule) {
return TagRuleOutput.builder()
.id(tagRule.getId())
.tagName(tagRule.getTag().getName())
.assets(
tagRule.getAssets().stream().collect(Collectors.toMap(Asset::getId, Asset::getName)))
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package io.openbas.rest.tag_rule.form;

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

import com.fasterxml.jackson.annotation.JsonProperty;
import jakarta.validation.constraints.NotBlank;
import java.util.HashMap;
import java.util.Map;
import lombok.Builder;
import lombok.EqualsAndHashCode;
import lombok.Getter;

@Builder(toBuilder = true)
@Getter
@EqualsAndHashCode
public class TagRuleOutput {
@NotBlank(message = MANDATORY_MESSAGE)
@JsonProperty("tag_rule_id")
private String id;

@NotBlank(message = MANDATORY_MESSAGE)
@JsonProperty("tag_name")
private String tagName;

@JsonProperty("tag_rule_assets")
Map<String, String> assets = new HashMap<>();
}
174 changes: 174 additions & 0 deletions openbas-api/src/main/java/io/openbas/service/TagRuleService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
package io.openbas.service;

import static io.openbas.utils.pagination.PaginationUtils.buildPaginationJPA;

import com.cronutils.utils.VisibleForTesting;
import io.openbas.database.model.Asset;
import io.openbas.database.model.Tag;
import io.openbas.database.model.TagRule;
import io.openbas.database.repository.AssetRepository;
import io.openbas.database.repository.TagRepository;
import io.openbas.database.repository.TagRuleRepository;
import io.openbas.rest.exception.ElementNotFoundException;
import io.openbas.utils.pagination.SearchPaginationInput;
import jakarta.validation.constraints.NotBlank;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;

@RequiredArgsConstructor
@Service
public class TagRuleService {
private TagRuleRepository tagRuleRepository;
private TagRepository tagRepository;
private AssetRepository assetRepository;

/**
* Find the TagRule by id
*
* @param id
* @return
*/
heditar marked this conversation as resolved.
Show resolved Hide resolved
public Optional<TagRule> findById(String id) {
return tagRuleRepository.findById(id);
heditar marked this conversation as resolved.
Show resolved Hide resolved
}

/**
* Find all the TagRules
*
* @return
*/
public List<TagRule> findAll() {
return StreamSupport.stream(tagRuleRepository.findAll().spliterator(), false)
.collect(Collectors.toList());
}

/**
* Create a TagRule
*
* @param tagName if the tag doesn't exist it will be created
* @param assetIds list of existing assets id
* @return
*/
public TagRule createTagRule(@NotBlank final String tagName, final List<String> assetIds) {
// if the tag doesn't exist we create it
// if one of the asset doesn't exist throw a ResourceNotFoundException
heditar marked this conversation as resolved.
Show resolved Hide resolved
TagRule tagRule = new TagRule();
tagRule.setTag(getOrCreateTag(tagName));
tagRule.setAssets(getAssets(assetIds));
return tagRuleRepository.save(tagRule);
}

/**
* Update tagRule
*
* @param tagName
* @param assetIds
* @return
*/
public TagRule updateTagRule(
@NotBlank final String tagRuleId, final String tagName, final List<String> assetIds) {

// verify that the tag rule exists
TagRule tagRule =
tagRuleRepository
.findById(tagRuleId)
.orElseThrow(
() -> new ElementNotFoundException("TagRule not found with id: " + tagRuleId));

// if the tag doesn't exist we create it
tagRule.setTag(getOrCreateTag(tagName));

// if one of the asset doesn't exist throw a ResourceNotFoundException
tagRule.setAssets(getAssets(assetIds));

return tagRuleRepository.save(tagRule);
}

/**
* Search TagRule
*
* @param searchPaginationInput
* @return
*/
public Page<TagRule> searchTagRule(SearchPaginationInput searchPaginationInput) {
return buildPaginationJPA(

Check warning on line 103 in openbas-api/src/main/java/io/openbas/service/TagRuleService.java

View check run for this annotation

Codecov / codecov/patch

openbas-api/src/main/java/io/openbas/service/TagRuleService.java#L103

Added line #L103 was not covered by tests
(Specification<TagRule> specification, Pageable pageable) ->
this.tagRuleRepository.findAll(specification, pageable),

Check warning on line 105 in openbas-api/src/main/java/io/openbas/service/TagRuleService.java

View check run for this annotation

Codecov / codecov/patch

openbas-api/src/main/java/io/openbas/service/TagRuleService.java#L105

Added line #L105 was not covered by tests
searchPaginationInput,
TagRule.class);
}

/**
* Delete a TagRule
*
* @param tagRuleId
*/
public void deleteTagRule(@NotBlank final String tagRuleId) {
this.tagRuleRepository.deleteById(tagRuleId);
}

@VisibleForTesting
protected Tag createtag(final String tagName) {
Tag tag = new Tag();
tag.setName(tagName);
return tag;
}

/**
* Check if the tag exists, if no it creates it
*
* @param tagName
* @return
*/
@VisibleForTesting
protected Tag getOrCreateTag(@NotBlank final String tagName) {
// TODO: tag name normalization needs to be implemented in a reusable method
return tagRepository
.findByName(tagName.toLowerCase())
.orElseGet(() -> tagRepository.save(createtag(tagName)));
}

/**
* Get the assets from the DB, and throwns an exception if an asset doesn't exist
*
* @param assetIds
* @return
*/
@VisibleForTesting
protected List<Asset> getAssets(final List<String> assetIds) {
return assetIds == null
? new ArrayList<>()

Check warning on line 149 in openbas-api/src/main/java/io/openbas/service/TagRuleService.java

View check run for this annotation

Codecov / codecov/patch

openbas-api/src/main/java/io/openbas/service/TagRuleService.java#L149

Added line #L149 was not covered by tests
: assetIds.stream()
.map(
id ->
assetRepository
.findById(id)
.orElseThrow(
() -> new ElementNotFoundException("Asset not found with id: " + id)))
.toList();
}

@Autowired
public void setTagRuleRepository(TagRuleRepository tagRuleRepository) {
this.tagRuleRepository = tagRuleRepository;
}

@Autowired
public void setTagRepository(TagRepository tagRepository) {
this.tagRepository = tagRepository;
}

@Autowired
public void setAssetRepository(AssetRepository assetRepository) {
this.assetRepository = assetRepository;
}
heditar marked this conversation as resolved.
Show resolved Hide resolved
}
Loading
Loading