Skip to content

Commit

Permalink
[backend] Asset, Endpoint & AssetGroup (#268)
Browse files Browse the repository at this point in the history
  • Loading branch information
RomuDeuxfois committed Dec 28, 2023
1 parent 88258e6 commit d76642b
Show file tree
Hide file tree
Showing 20 changed files with 662 additions and 1 deletion.
1 change: 0 additions & 1 deletion openex-api/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
<commons-codec.version>1.16.0</commons-codec.version>
<commons-collections4.version>4.4</commons-collections4.version>
<commons-email.version>1.5</commons-email.version>
<commons-validator.version>1.7</commons-validator.version>
<flyway.version>9.0.3</flyway.version>
<opensaml.version>4.1.1</opensaml.version>
<springdoc.version>1.7.0</springdoc.version>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package io.openex.migration;

import org.flywaydb.core.api.migration.BaseJavaMigration;
import org.flywaydb.core.api.migration.Context;
import org.springframework.stereotype.Component;

import java.sql.Connection;
import java.sql.Statement;

@Component
public class V2_64__Assets_Asset_Groups extends BaseJavaMigration {

@Override
public void migrate(Context context) throws Exception {
Connection connection = context.getConnection();
Statement select = connection.createStatement();
// Create table asset
select.execute("""
CREATE TABLE IF NOT EXISTS assets (
asset_id varchar(255) not null constraint assets_pkey primary key,
asset_external_id varchar(255),
asset_name varchar(255) not null,
asset_description text,
asset_created_at timestamp not null default now(),
asset_updated_at timestamp not null default now()
);
CREATE INDEX IF NOT EXISTS idx_assets on assets (asset_id);
""");
// Create table endpoint
select.execute("""
CREATE TABLE IF NOT EXISTS endpoints (
endpoint_ip varchar(255) not null constraint endpoint_pkey primary key,
endpoint_hostname varchar(255),
endpoint_os varchar(255)
) INHERITS (assets);
""");
// Create table asset groups
select.execute("""
CREATE TABLE IF NOT EXISTS asset_groups (
asset_group_id varchar(255) not null constraint asset_groups_pkey primary key,
asset_group_name varchar(255) not null,
asset_group_description text,
asset_group_created_at timestamp not null default now(),
asset_group_updated_at timestamp not null default now()
);
CREATE INDEX IF NOT EXISTS idx_asset_groups on asset_groups (asset_group_id);
""");
// Add association table between asset and asset groups
select.execute("""
CREATE TABLE IF NOT EXISTS asset_groups_assets (
asset_group_id varchar(255) not null constraint asset_group_id_fk references asset_groups on delete cascade,
asset_id varchar(255) not null constraint asset_id_fk references endpoints on delete cascade,
constraint asset_groups_assets_pkey primary key (asset_group_id, asset_id)
);
CREATE INDEX IF NOT EXISTS idx_asset_groups_assets_asset on asset_groups_assets (asset_group_id);
CREATE INDEX IF NOT EXISTS idx_asset_groups_assets_asset on asset_groups_assets (asset_id);
""");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package io.openex.rest.asset.endpoint;

import io.openex.database.model.Endpoint;
import io.openex.rest.asset.endpoint.form.EndpointInput;
import io.openex.service.asset.EndpointService;
import lombok.RequiredArgsConstructor;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;

import javax.annotation.security.RolesAllowed;
import javax.validation.Valid;
import javax.validation.constraints.NotBlank;
import java.util.List;

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

@RequiredArgsConstructor
@RestController
public class EndpointApi {

public static final String ENDPOINT_URI = "/api/endpoints";

private final EndpointService endpointService;

@PostMapping(ENDPOINT_URI)
@RolesAllowed(ROLE_ADMIN)
public Endpoint createEndpoint(@Valid @RequestBody final EndpointInput input) {
Endpoint endpoint = new Endpoint();
endpoint.setUpdateAttributes(input);
return this.endpointService.createEndpoint(endpoint);
}

@GetMapping(ENDPOINT_URI)
@PreAuthorize("isObserver()")
public List<Endpoint> endpoints() {
return this.endpointService.endpoints();
}

@PutMapping(ENDPOINT_URI + "/{endpointId}")
@RolesAllowed(ROLE_ADMIN)
public Endpoint updateEndpoint(
@PathVariable @NotBlank final String endpointId,
@Valid @RequestBody final EndpointInput input) {
Endpoint endpoint = this.endpointService.endpoint(endpointId);
endpoint.setUpdateAttributes(input);
return this.endpointService.updateEndpoint(endpoint);
}

@DeleteMapping(ENDPOINT_URI + "/{endpointId}")
@RolesAllowed(ROLE_ADMIN)
public void deleteEndpoint(@PathVariable @NotBlank final String endpointId) {
this.endpointService.deleteEndpoint(endpointId);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package io.openex.rest.asset.endpoint.form;

import com.fasterxml.jackson.annotation.JsonProperty;
import io.openex.rest.asset.form.AssetInput;
import lombok.Data;
import lombok.EqualsAndHashCode;

import javax.validation.constraints.NotBlank;

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

@EqualsAndHashCode(callSuper = true)
@Data
public class EndpointInput extends AssetInput {


@NotBlank(message = MANDATORY_MESSAGE)
@JsonProperty("endpoint_ip")
private String ip;

@JsonProperty("endpoint_hostname")
private String hostname;

@NotBlank(message = MANDATORY_MESSAGE)
@JsonProperty("endpoint_os")
private String os;

}
20 changes: 20 additions & 0 deletions openex-api/src/main/java/io/openex/rest/asset/form/AssetInput.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package io.openex.rest.asset.form;

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

import javax.validation.constraints.NotBlank;

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

@Data
public abstract class AssetInput {

@JsonProperty("asset_external_id")
private String externalId;

@NotBlank(message = MANDATORY_MESSAGE)
@JsonProperty("asset_name")
private String name;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package io.openex.rest.asset_group.form;

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

import javax.validation.constraints.NotBlank;

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

@Getter
@Setter
public class AssetGroupInput {

@NotBlank(message = MANDATORY_MESSAGE)
@JsonProperty("asset_group_name")
private String name;

@JsonProperty("asset_group_description")
private String description;
}
42 changes: 42 additions & 0 deletions openex-api/src/main/java/io/openex/service/AssetGroupService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package io.openex.service;

import io.openex.database.model.AssetGroup;
import io.openex.database.repository.AssetGroupRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.util.List;

import static io.openex.helper.StreamHelper.fromIterable;
import static java.time.Instant.now;

@RequiredArgsConstructor
@Service
public class AssetGroupService {

private final AssetGroupRepository assetGroupRepository;

public AssetGroup createAssetGroup(@NotNull final AssetGroup assetGroup) {
return this.assetGroupRepository.save(assetGroup);
}

public AssetGroup assetGroup(@NotBlank final String assetGroupId) {
return this.assetGroupRepository.findById(assetGroupId).orElseThrow();
}

public List<AssetGroup> assetGroups() {
return fromIterable(this.assetGroupRepository.findAll());
}

public AssetGroup updateAssetGroup(@NotNull final AssetGroup assetGroup) {
assetGroup.setUpdatedAt(now());
return this.assetGroupRepository.save(assetGroup);
}

public void deleteAssetGroup(@NotBlank final String assetGroupId) {
this.assetGroupRepository.deleteById(assetGroupId);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package io.openex.service.asset;

import io.openex.database.model.Endpoint;
import io.openex.database.repository.EndpointRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.util.List;

import static io.openex.helper.StreamHelper.fromIterable;
import static java.time.Instant.now;

@RequiredArgsConstructor
@Service
public class EndpointService {

private final EndpointRepository endpointRepository;

public Endpoint createEndpoint(@NotNull final Endpoint endpoint) {
return this.endpointRepository.save(endpoint);
}

public Endpoint endpoint(@NotBlank final String endpointId) {
return this.endpointRepository.findById(endpointId).orElseThrow();
}

public List<Endpoint> endpoints() {
return fromIterable(this.endpointRepository.findAll());
}

public Endpoint updateEndpoint(@NotNull final Endpoint endpoint) {
endpoint.setUpdatedAt(now());
return this.endpointRepository.save(endpoint);
}

public void deleteEndpoint(@NotBlank final String endpointId) {
this.endpointRepository.deleteById(endpointId);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package io.openex.service;

import io.openex.database.model.Endpoint;
import io.openex.database.model.AssetGroup;
import io.openex.service.asset.EndpointService;
import org.junit.jupiter.api.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;
import java.util.NoSuchElementException;

import static io.openex.database.model.Endpoint.OS_TYPE.LINUX;
import static org.junit.jupiter.api.Assertions.*;

@SpringBootTest
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class AssetGroupServiceTest {

@Autowired
private AssetGroupService assetGroupService;
@Autowired
private EndpointService endpointService;

static String ASSET_GROUP_ID;

@DisplayName("Create asset group")
@Test
@Order(1)
void createAssetGroupTest() {
// -- PREPARE --
AssetGroup assetGroup = new AssetGroup();
String name = "Personal network";
assetGroup.setName(name);

// -- EXECUTE --
AssetGroup assetGroupCreated = this.assetGroupService.createAssetGroup(assetGroup);
ASSET_GROUP_ID = assetGroupCreated.getId();
assertNotNull(assetGroupCreated);
assertNotNull(assetGroupCreated.getId());
assertNotNull(assetGroupCreated.getCreatedAt());
assertNotNull(assetGroupCreated.getUpdatedAt());
assertEquals(name, assetGroupCreated.getName());
}

@DisplayName("Retrieve asset group")
@Test
@Order(2)
void retrieveAssetGroupTest() {
AssetGroup assetGroup = this.assetGroupService.assetGroup(ASSET_GROUP_ID);
assertNotNull(assetGroup);

List<AssetGroup> assetGroups = this.assetGroupService.assetGroups();
assertNotNull(assetGroups);
assertEquals(ASSET_GROUP_ID, assetGroups.get(0).getId());
}

@DisplayName("Update asset group")
@Test
@Order(3)
void updateAssetGroupTest() {
// -- PREPARE --
Endpoint endpoint = new Endpoint();
String name = "Personal PC";
endpoint.setName(name);
endpoint.setIp("127.0.0.1");
endpoint.setHostname("hostname");
endpoint.setOs(LINUX);
endpoint.setHostname("hostname");
endpoint.setOs(LINUX);
Endpoint endpointCreated = this.endpointService.createEndpoint(endpoint);

AssetGroup assetGroup = this.assetGroupService.assetGroup(ASSET_GROUP_ID);
String value = "Professional network";
assetGroup.setName(value);
assetGroup.setAssets(List.of(endpointCreated));

// -- EXECUTE --
AssetGroup assetGroupUpdated = this.assetGroupService.updateAssetGroup(assetGroup);
assertNotNull(assetGroup);
assertEquals(value, assetGroupUpdated.getName());
}

@DisplayName("Delete asset group")
@Test
@Order(4)
void deleteAssetGroupTest() {
this.assetGroupService.deleteAssetGroup(ASSET_GROUP_ID);
assertThrows(NoSuchElementException.class, () -> this.assetGroupService.assetGroup(ASSET_GROUP_ID));
}
}
Loading

0 comments on commit d76642b

Please sign in to comment.